diff --git a/admin/src/plugins/apolloProvider.js b/admin/src/plugins/apolloProvider.js index 1f51be20a..95b7aab7e 100644 --- a/admin/src/plugins/apolloProvider.js +++ b/admin/src/plugins/apolloProvider.js @@ -10,6 +10,7 @@ const authLink = new ApolloLink((operation, forward) => { operation.setContext({ headers: { Authorization: token && token.length > 0 ? `Bearer ${token}` : '', + clientRequestTime: new Date().toString(), }, }) return forward(operation).map((response) => { diff --git a/admin/src/plugins/apolloProvider.test.js b/admin/src/plugins/apolloProvider.test.js index 75e415901..7889c3318 100644 --- a/admin/src/plugins/apolloProvider.test.js +++ b/admin/src/plugins/apolloProvider.test.js @@ -94,6 +94,7 @@ describe('apolloProvider', () => { expect(setContextMock).toBeCalledWith({ headers: { Authorization: 'Bearer some-token', + clientRequestTime: expect.any(String), }, }) }) @@ -109,6 +110,7 @@ describe('apolloProvider', () => { expect(setContextMock).toBeCalledWith({ headers: { Authorization: '', + clientRequestTime: expect.any(String), }, }) }) diff --git a/backend/.env.dist b/backend/.env.dist index 69b1d6a46..648a2054c 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -1,4 +1,4 @@ -CONFIG_VERSION=v9.2022-07-07 +CONFIG_VERSION=v10.2022-09-20 # Server PORT=4000 @@ -37,6 +37,8 @@ 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 diff --git a/backend/.env.template b/backend/.env.template index beaa256ef..dddf845dc 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -36,6 +36,8 @@ LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a # EMail EMAIL=$EMAIL +EMAIL_TEST_MODUS=$EMAIL_TEST_MODUS +EMAIL_TEST_RECEIVER=$EMAIL_TEST_RECEIVER EMAIL_USERNAME=$EMAIL_USERNAME EMAIL_SENDER=$EMAIL_SENDER EMAIL_PASSWORD=$EMAIL_PASSWORD diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 6a2ebba87..3e6bafd9f 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,14 +10,14 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0048-add_is_moderator_to_contribution_messages', + DB_VERSION: '0049-add_user_contacts_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 LOG_LEVEL: process.env.LOG_LEVEL || 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v9.2022-07-07', + EXPECTED: 'v10.2022-09-20', CURRENT: '', }, } @@ -67,6 +67,8 @@ const loginServer = { const email = { EMAIL: process.env.EMAIL === 'true' || false, + EMAIL_TEST_MODUS: process.env.EMAIL_TEST_MODUS === 'true' || 'false', + EMAIL_TEST_RECEIVER: process.env.EMAIL_TEST_RECEIVER || 'stage1@gradido.net', EMAIL_USERNAME: process.env.EMAIL_USERNAME || 'gradido_email', EMAIL_SENDER: process.env.EMAIL_SENDER || 'info@gradido.net', EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx', diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 6f07661f1..85fba896d 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -32,6 +32,7 @@ export class EventRegister extends EventBasicUserId {} export class EventRedeemRegister extends EventBasicRedeem {} export class EventInactiveAccount extends EventBasicUserId {} export class EventSendConfirmationEmail extends EventBasicUserId {} +export class EventSendAccountMultiRegistrationEmail extends EventBasicUserId {} export class EventConfirmationEmail extends EventBasicUserId {} export class EventRegisterEmailKlicktipp extends EventBasicUserId {} export class EventLogin extends EventBasicUserId {} @@ -113,6 +114,15 @@ export class Event { return this } + public setEventSendAccountMultiRegistrationEmail( + ev: EventSendAccountMultiRegistrationEmail, + ): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.SEND_ACCOUNT_MULTI_REGISTRATION_EMAIL + + return this + } + public setEventConfirmationEmail(ev: EventConfirmationEmail): Event { this.setByBasicUser(ev.userId) this.type = EventProtocolType.CONFIRM_EMAIL diff --git a/backend/src/event/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts index 0f61f787a..52bcf8349 100644 --- a/backend/src/event/EventProtocolType.ts +++ b/backend/src/event/EventProtocolType.ts @@ -5,6 +5,7 @@ export enum EventProtocolType { REDEEM_REGISTER = 'REDEEM_REGISTER', INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT', SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL', + SEND_ACCOUNT_MULTI_REGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTI_REGISTRATION_EMAIL', CONFIRM_EMAIL = 'CONFIRM_EMAIL', REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP', LOGIN = 'LOGIN', diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index 065c01957..c24cde47a 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -31,7 +31,7 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { // TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests // TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey - const userRepository = await getCustomRepository(UserRepository) + const userRepository = getCustomRepository(UserRepository) try { const user = await userRepository.findByPubkeyHex(context.pubKey) context.user = user diff --git a/backend/src/graphql/enum/UserContactType.ts b/backend/src/graphql/enum/UserContactType.ts new file mode 100644 index 000000000..93c83830c --- /dev/null +++ b/backend/src/graphql/enum/UserContactType.ts @@ -0,0 +1,11 @@ +import { registerEnumType } from 'type-graphql' + +export enum UserContactType { + USER_CONTACT_EMAIL = 'EMAIL', + USER_CONTACT_PHONE = 'PHONE', +} + +registerEnumType(UserContactType, { + name: 'UserContactType', // this one is mandatory + description: 'Type of the user contact', // this one is optional +}) diff --git a/backend/src/graphql/model/UnconfirmedContribution.ts b/backend/src/graphql/model/UnconfirmedContribution.ts index 5847b08d0..c42b4fd11 100644 --- a/backend/src/graphql/model/UnconfirmedContribution.ts +++ b/backend/src/graphql/model/UnconfirmedContribution.ts @@ -13,7 +13,7 @@ export class UnconfirmedContribution { this.date = contribution.contributionDate this.firstName = user ? user.firstName : '' this.lastName = user ? user.lastName : '' - this.email = user ? user.email : '' + this.email = user ? user.emailContact.email : '' this.moderator = contribution.moderatorId this.creation = creations this.state = contribution.contributionStatus diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index 1ec33b27d..cc52ff1f1 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -3,6 +3,7 @@ import { KlickTipp } from './KlickTipp' import { User as dbUser } from '@entity/User' import Decimal from 'decimal.js-light' import { FULL_CREATION_AVAILABLE } from '../resolver/const/const' +import { UserContact } from './UserContact' @ObjectType() export class User { @@ -10,12 +11,16 @@ export class User { this.id = user.id this.gradidoID = user.gradidoID this.alias = user.alias - this.email = user.email + this.emailId = user.emailId + if (user.emailContact) { + this.email = user.emailContact.email + this.emailContact = new UserContact(user.emailContact) + this.emailChecked = user.emailContact.emailChecked + } this.firstName = user.firstName this.lastName = user.lastName this.deletedAt = user.deletedAt this.createdAt = user.createdAt - this.emailChecked = user.emailChecked this.language = user.language this.publisherId = user.publisherId this.isAdmin = user.isAdmin @@ -34,12 +39,18 @@ export class User { gradidoID: string @Field(() => String, { nullable: true }) - alias: string + alias?: string + + @Field(() => Number, { nullable: true }) + emailId: number | null // TODO privacy issue here - @Field(() => String) + @Field(() => String, { nullable: true }) email: string + @Field(() => UserContact) + emailContact: UserContact + @Field(() => String, { nullable: true }) firstName: string | null diff --git a/backend/src/graphql/model/UserAdmin.ts b/backend/src/graphql/model/UserAdmin.ts index cf3663e70..08dc405ac 100644 --- a/backend/src/graphql/model/UserAdmin.ts +++ b/backend/src/graphql/model/UserAdmin.ts @@ -6,11 +6,11 @@ import { User } from '@entity/User' export class UserAdmin { constructor(user: User, creation: Decimal[], hasElopage: boolean, emailConfirmationSend: string) { this.userId = user.id - this.email = user.email + this.email = user.emailContact.email this.firstName = user.firstName this.lastName = user.lastName this.creation = creation - this.emailChecked = user.emailChecked + this.emailChecked = user.emailContact.emailChecked this.hasElopage = hasElopage this.deletedAt = user.deletedAt this.emailConfirmationSend = emailConfirmationSend diff --git a/backend/src/graphql/model/UserContact.ts b/backend/src/graphql/model/UserContact.ts new file mode 100644 index 000000000..796c7f5f3 --- /dev/null +++ b/backend/src/graphql/model/UserContact.ts @@ -0,0 +1,56 @@ +import { ObjectType, Field } from 'type-graphql' +import { UserContact as dbUserContact } from '@entity/UserContact' + +@ObjectType() +export class UserContact { + constructor(userContact: dbUserContact) { + this.id = userContact.id + this.type = userContact.type + this.userId = userContact.userId + this.email = userContact.email + // this.emailVerificationCode = userContact.emailVerificationCode + this.emailOptInTypeId = userContact.emailOptInTypeId + this.emailResendCount = userContact.emailResendCount + this.emailChecked = userContact.emailChecked + this.phone = userContact.phone + this.createdAt = userContact.createdAt + this.updatedAt = userContact.updatedAt + this.deletedAt = userContact.deletedAt + } + + @Field(() => Number) + id: number + + @Field(() => String) + type: string + + @Field(() => Number) + userId: number + + @Field(() => String) + email: string + + // @Field(() => BigInt, { nullable: true }) + // emailVerificationCode: BigInt | null + + @Field(() => Number, { nullable: true }) + emailOptInTypeId: number | null + + @Field(() => Number, { nullable: true }) + emailResendCount: number | null + + @Field(() => Boolean) + emailChecked: boolean + + @Field(() => String, { nullable: true }) + phone: string | null + + @Field(() => Date) + createdAt: Date + + @Field(() => Date, { nullable: true }) + updatedAt: Date | null + + @Field(() => Date, { nullable: true }) + deletedAt: Date | null +} diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index f0ce064b4..b1b4e469e 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -40,6 +40,7 @@ import Decimal from 'decimal.js-light' import { Contribution } from '@entity/Contribution' import { Transaction as DbTransaction } from '@entity/Transaction' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' // mock account activation email to avoid console spam jest.mock('@/mailer/sendAccountActivationEmail', () => { @@ -49,6 +50,14 @@ jest.mock('@/mailer/sendAccountActivationEmail', () => { } }) +// mock account activation email to avoid console spam +jest.mock('@/mailer/sendContributionConfirmedEmail', () => { + return { + __esModule: true, + sendContributionConfirmedEmail: jest.fn(), + } +}) + let mutate: any, query: any, con: any let testEnv: any @@ -1117,7 +1126,9 @@ describe('AdminResolver', () => { }), ).resolves.toEqual( expect.objectContaining({ - errors: [new GraphQLError('Could not find user with email: bob@baumeister.de')], + errors: [ + new GraphQLError('Could not find UserContact with email: bob@baumeister.de'), + ], }), ) }) @@ -1450,6 +1461,20 @@ describe('AdminResolver', () => { expect(transaction[0].linkedUserId).toEqual(null) expect(transaction[0].typeId).toEqual(1) }) + + it('calls sendContributionConfirmedEmail', async () => { + expect(sendContributionConfirmedEmail).toBeCalledWith( + expect.objectContaining({ + contributionMemo: 'Herzlich Willkommen bei Gradido liebe Bibi!', + overviewURL: 'http://localhost/overview', + recipientEmail: 'bibi@bloxberg.de', + recipientFirstName: 'Bibi', + recipientLastName: 'Bloxberg', + senderFirstName: 'Peter', + senderLastName: 'Lustig', + }), + ) + }) }) describe('confirm two creations one after the other quickly', () => { @@ -1493,6 +1518,7 @@ describe('AdminResolver', () => { ) await expect(r2).resolves.toEqual( expect.objectContaining({ + // data: { confirmContribution: true }, errors: [new GraphQLError('Creation was not successful.')], }), ) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index ac3936e4f..e9ee0b55b 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -4,8 +4,6 @@ import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx, Int } from 'type import { getCustomRepository, IsNull, - Not, - ObjectLiteral, getConnection, In, MoreThan, @@ -32,7 +30,6 @@ import { TransactionRepository } from '@repository/Transaction' import { calculateDecay } from '@/util/decay' import { Contribution } from '@entity/Contribution' import { hasElopageBuys } from '@/util/hasElopageBuys' -import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User as dbUser } from '@entity/User' import { User } from '@model/User' import { TransactionTypeId } from '@enum/TransactionTypeId' @@ -44,7 +41,7 @@ import Paginated from '@arg/Paginated' import TransactionLinkFilters from '@arg/TransactionLinkFilters' import { Order } from '@enum/Order' import { communityUser } from '@/util/communityUser' -import { checkOptInCode, activationLink, printTimeDuration } from './UserResolver' +import { findUserByEmail, activationLink, printTimeDuration } from './UserResolver' import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' import CONFIG from '@/config' @@ -62,10 +59,13 @@ import { MEMO_MAX_CHARS, MEMO_MIN_CHARS, } from './const/const' +import { UserContact } from '@entity/UserContact' import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage' import ContributionMessageArgs from '@arg/ContributionMessageArgs' import { ContributionMessageType } from '@enum/MessageType' import { ContributionMessage } from '@model/ContributionMessage' +import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' +import { sendAddedContributionMessageEmail } from '@/mailer/sendAddedContributionMessageEmail' // const EMAIL_OPT_IN_REGISTER = 1 // const EMAIL_OPT_UNKNOWN = 3 // elopage? @@ -79,24 +79,12 @@ export class AdminResolver { { searchText, currentPage = 1, pageSize = 25, filters }: SearchUsersArgs, ): Promise { const userRepository = getCustomRepository(UserRepository) - - const filterCriteria: ObjectLiteral[] = [] - if (filters) { - if (filters.byActivated !== null) { - filterCriteria.push({ emailChecked: filters.byActivated }) - } - - if (filters.byDeleted !== null) { - filterCriteria.push({ deletedAt: filters.byDeleted ? Not(IsNull()) : IsNull() }) - } - } - const userFields = [ 'id', 'firstName', 'lastName', - 'email', - 'emailChecked', + 'emailId', + 'emailContact', 'deletedAt', 'isAdmin', ] @@ -105,7 +93,7 @@ export class AdminResolver { return 'user.' + fieldName }), searchText, - filterCriteria, + filters, currentPage, pageSize, ) @@ -122,32 +110,18 @@ export class AdminResolver { const adminUsers = await Promise.all( users.map(async (user) => { let emailConfirmationSend = '' - if (!user.emailChecked) { - const emailOptIn = await LoginEmailOptIn.findOne( - { - userId: user.id, - }, - { - order: { - updatedAt: 'DESC', - createdAt: 'DESC', - }, - select: ['updatedAt', 'createdAt'], - }, - ) - if (emailOptIn) { - if (emailOptIn.updatedAt) { - emailConfirmationSend = emailOptIn.updatedAt.toISOString() - } else { - emailConfirmationSend = emailOptIn.createdAt.toISOString() - } + if (!user.emailContact.emailChecked) { + if (user.emailContact.updatedAt) { + emailConfirmationSend = user.emailContact.updatedAt.toISOString() + } else { + emailConfirmationSend = user.emailContact.createdAt.toISOString() } } const userCreations = creations.find((c) => c.id === user.id) const adminUser = new UserAdmin( user, userCreations ? userCreations.creations : FULL_CREATION_AVAILABLE, - await hasElopageBuys(user.email), + await hasElopageBuys(user.emailContact.email), emailConfirmationSend, ) return adminUser @@ -243,24 +217,39 @@ export class AdminResolver { @Args() { email, amount, memo, creationDate }: AdminCreateContributionArgs, @Ctx() context: Context, ): Promise { - const user = await dbUser.findOne({ email }, { withDeleted: true }) - if (!user) { + logger.info( + `adminCreateContribution(email=${email}, amount=${amount}, memo=${memo}, creationDate=${creationDate})`, + ) + const emailContact = await UserContact.findOne({ + where: { email }, + withDeleted: true, + relations: ['user'], + }) + if (!emailContact) { + logger.error(`Could not find user with email: ${email}`) throw new Error(`Could not find user with email: ${email}`) } - if (user.deletedAt) { + if (emailContact.deletedAt) { + logger.error('This emailContact was deleted. Cannot create a contribution.') + throw new Error('This emailContact was deleted. Cannot create a contribution.') + } + if (emailContact.user.deletedAt) { + logger.error('This user was deleted. Cannot create a contribution.') throw new Error('This user was deleted. Cannot create a contribution.') } - if (!user.emailChecked) { + if (!emailContact.emailChecked) { + logger.error('Contribution could not be saved, Email is not activated') throw new Error('Contribution could not be saved, Email is not activated') } const moderator = getUser(context) logger.trace('moderator: ', moderator.id) - const creations = await getUserCreation(user.id) - logger.trace('creations', creations) + const creations = await getUserCreation(emailContact.userId) + logger.trace('creations:', creations) const creationDateObj = new Date(creationDate) + logger.trace('creationDateObj:', creationDateObj) validateContribution(creations, amount, creationDateObj) const contribution = Contribution.create() - contribution.userId = user.id + contribution.userId = emailContact.userId contribution.amount = amount contribution.createdAt = new Date() contribution.contributionDate = creationDateObj @@ -271,7 +260,7 @@ export class AdminResolver { logger.trace('contribution to save', contribution) await Contribution.save(contribution) - return getUserCreation(user.id) + return getUserCreation(emailContact.userId) } @Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTIONS]) @@ -307,11 +296,22 @@ export class AdminResolver { @Args() { id, email, amount, memo, creationDate }: AdminUpdateContributionArgs, @Ctx() context: Context, ): Promise { - const user = await dbUser.findOne({ email }, { withDeleted: true }) + const emailContact = await UserContact.findOne({ + where: { email }, + withDeleted: true, + relations: ['user'], + }) + if (!emailContact) { + logger.error(`Could not find UserContact with email: ${email}`) + throw new Error(`Could not find UserContact with email: ${email}`) + } + const user = emailContact.user if (!user) { - throw new Error(`Could not find user with email: ${email}`) + logger.error(`Could not find User to emailContact: ${email}`) + throw new Error(`Could not find User to emailContact: ${email}`) } if (user.deletedAt) { + logger.error(`User was deleted (${email})`) throw new Error(`User was deleted (${email})`) } @@ -322,14 +322,17 @@ export class AdminResolver { }) if (!contributionToUpdate) { + logger.error('No contribution found to given id.') throw new Error('No contribution found to given id.') } if (contributionToUpdate.userId !== user.id) { + logger.error('user of the pending contribution and send user does not correspond') throw new Error('user of the pending contribution and send user does not correspond') } if (contributionToUpdate.moderatorId === null) { + logger.error('An admin is not allowed to update a user contribution.') throw new Error('An admin is not allowed to update a user contribution.') } @@ -375,7 +378,11 @@ export class AdminResolver { const userIds = contributions.map((p) => p.userId) const userCreations = await getUserCreations(userIds) - const users = await dbUser.find({ where: { id: In(userIds) }, withDeleted: true }) + const users = await dbUser.find({ + where: { id: In(userIds) }, + withDeleted: true, + relations: ['emailContact'], + }) return contributions.map((contribution) => { const user = users.find((u) => u.id === contribution.userId) @@ -394,6 +401,7 @@ export class AdminResolver { async adminDeleteContribution(@Arg('id', () => Int) id: number): Promise { const contribution = await Contribution.findOne(id) if (!contribution) { + logger.error(`Contribution not found for given id: ${id}`) throw new Error('Contribution not found for given id.') } contribution.contributionStatus = ContributionStatus.DELETED @@ -410,15 +418,22 @@ export class AdminResolver { ): Promise { const contribution = await Contribution.findOne(id) if (!contribution) { + logger.error(`Contribution not found for given id: ${id}`) throw new Error('Contribution not found to given id.') } const moderatorUser = getUser(context) - if (moderatorUser.id === contribution.userId) + if (moderatorUser.id === contribution.userId) { + logger.error('Moderator can not confirm own contribution') throw new Error('Moderator can not confirm own contribution') - - const user = await dbUser.findOneOrFail({ id: contribution.userId }, { withDeleted: true }) - if (user.deletedAt) throw new Error('This user was deleted. Cannot confirm a contribution.') - + } + const user = await dbUser.findOneOrFail( + { id: contribution.userId }, + { withDeleted: true, relations: ['emailContact'] }, + ) + if (user.deletedAt) { + logger.error('This user was deleted. Cannot confirm a contribution.') + throw new Error('This user was deleted. Cannot confirm a contribution.') + } const creations = await getUserCreation(contribution.userId, false) validateContribution(creations, contribution.amount, contribution.contributionDate) @@ -426,7 +441,7 @@ export class AdminResolver { const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() - await queryRunner.startTransaction('READ UNCOMMITTED') + await queryRunner.startTransaction('REPEATABLE READ') // 'READ COMMITTED') try { const lastTransaction = await queryRunner.manager .createQueryBuilder() @@ -470,6 +485,16 @@ export class AdminResolver { await queryRunner.commitTransaction() logger.info('creation commited successfuly.') + sendContributionConfirmedEmail({ + senderFirstName: moderatorUser.firstName, + senderLastName: moderatorUser.lastName, + recipientFirstName: user.firstName, + recipientLastName: user.lastName, + recipientEmail: user.emailContact.email, + contributionMemo: contribution.memo, + contributionAmount: contribution.amount, + overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, + }) } catch (e) { await queryRunner.rollbackTransaction() logger.error(`Creation was not successful: ${e}`) @@ -505,32 +530,35 @@ export class AdminResolver { @Mutation(() => Boolean) async sendActivationEmail(@Arg('email') email: string): Promise { email = email.trim().toLowerCase() - const user = await dbUser.findOneOrFail({ email: email }) - - // can be both types: REGISTER and RESET_PASSWORD - let optInCode = await LoginEmailOptIn.findOne({ - where: { userId: user.id }, - order: { updatedAt: 'DESC' }, - }) - - optInCode = await checkOptInCode(optInCode, user) + // const user = await dbUser.findOne({ id: emailContact.userId }) + const user = await findUserByEmail(email) + if (!user) { + logger.error(`Could not find User to emailContact: ${email}`) + throw new Error(`Could not find User to emailContact: ${email}`) + } + if (user.deletedAt) { + logger.error(`User with emailContact: ${email} is deleted.`) + throw new Error(`User with emailContact: ${email} is deleted.`) + } + const emailContact = user.emailContact + if (emailContact.deletedAt) { + logger.error(`The emailContact: ${email} of htis User is deleted.`) + throw new Error(`The emailContact: ${email} of htis User is deleted.`) + } // eslint-disable-next-line @typescript-eslint/no-unused-vars const emailSent = await sendAccountActivationEmail({ - link: activationLink(optInCode), + link: activationLink(emailContact.emailVerificationCode), firstName: user.firstName, lastName: user.lastName, email, duration: printTimeDuration(CONFIG.EMAIL_CODE_VALID_TIME), }) - /* uncomment this, when you need the activation link on the console // In case EMails are disabled log the activation link for the user if (!emailSent) { - // eslint-disable-next-line no-console - console.log(`Account confirmation link: ${activationLink}`) + logger.info(`Account confirmation link: ${activationLink}`) } - */ return true } @@ -708,18 +736,29 @@ export class AdminResolver { @Ctx() context: Context, ): Promise { const user = getUser(context) + if (!user.emailContact) { + user.emailContact = await UserContact.findOneOrFail({ where: { id: user.emailId } }) + } const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() - await queryRunner.startTransaction('READ UNCOMMITTED') + await queryRunner.startTransaction('REPEATABLE READ') const contributionMessage = DbContributionMessage.create() try { - const contribution = await Contribution.findOne({ id: contributionId }) + const contribution = await Contribution.findOne({ + where: { id: contributionId }, + relations: ['user'], + }) if (!contribution) { throw new Error('Contribution not found') } if (contribution.userId === user.id) { throw new Error('Admin can not answer on own contribution') } + if (!contribution.user.emailContact) { + contribution.user.emailContact = await UserContact.findOneOrFail({ + where: { id: contribution.user.emailId }, + }) + } contributionMessage.contributionId = contributionId contributionMessage.createdAt = new Date() contributionMessage.message = message @@ -736,6 +775,18 @@ export class AdminResolver { contribution.contributionStatus = ContributionStatus.IN_PROGRESS await queryRunner.manager.update(Contribution, { id: contributionId }, contribution) } + + await sendAddedContributionMessageEmail({ + senderFirstName: user.firstName, + senderLastName: user.lastName, + recipientFirstName: contribution.user.firstName, + recipientLastName: contribution.user.lastName, + recipientEmail: contribution.user.emailContact.email, + senderEmail: user.emailContact.email, + contributionMemo: contribution.memo, + message, + overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, + }) await queryRunner.commitTransaction() } catch (e) { await queryRunner.rollbackTransaction() diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index c0e330750..40e9e2ace 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -12,6 +12,14 @@ import { listContributionMessages, login } from '@/seeds/graphql/queries' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' +import { sendAddedContributionMessageEmail } from '@/mailer/sendAddedContributionMessageEmail' + +jest.mock('@/mailer/sendAddedContributionMessageEmail', () => { + return { + __esModule: true, + sendAddedContributionMessageEmail: jest.fn(), + } +}) let mutate: any, query: any, con: any let testEnv: any @@ -151,6 +159,20 @@ describe('ContributionMessageResolver', () => { }), ) }) + + it('calls sendAddedContributionMessageEmail', async () => { + expect(sendAddedContributionMessageEmail).toBeCalledWith({ + senderFirstName: 'Peter', + senderLastName: 'Lustig', + recipientFirstName: 'Bibi', + recipientLastName: 'Bloxberg', + recipientEmail: 'bibi@bloxberg.de', + senderEmail: 'peter@lustig.de', + contributionMemo: 'Test env contribution', + message: 'Admin Test', + overviewURL: 'http://localhost/overview', + }) + }) }) }) }) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index fb92806d0..0b33c4722 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -23,7 +23,7 @@ export class ContributionMessageResolver { const user = getUser(context) const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() - await queryRunner.startTransaction('READ UNCOMMITTED') + await queryRunner.startTransaction('REPEATABLE READ') const contributionMessage = DbContributionMessage.create() try { const contribution = await Contribution.findOne({ id: contributionId }) diff --git a/backend/src/graphql/resolver/GdtResolver.ts b/backend/src/graphql/resolver/GdtResolver.ts index 56a95c9f0..a1d75e946 100644 --- a/backend/src/graphql/resolver/GdtResolver.ts +++ b/backend/src/graphql/resolver/GdtResolver.ts @@ -20,7 +20,7 @@ export class GdtResolver { try { const resultGDT = await apiGet( - `${CONFIG.GDT_API_URL}/GdtEntries/listPerEmailApi/${userEntity.email}/${currentPage}/${pageSize}/${order}`, + `${CONFIG.GDT_API_URL}/GdtEntries/listPerEmailApi/${userEntity.emailContact.email}/${currentPage}/${pageSize}/${order}`, ) if (!resultGDT.success) { throw new Error(resultGDT.data) @@ -37,7 +37,7 @@ export class GdtResolver { const user = getUser(context) try { const resultGDTSum = await apiPost(`${CONFIG.GDT_API_URL}/GdtEntries/sumPerEmailApi`, { - email: user.email, + email: user.emailContact.email, }) if (!resultGDTSum.success) { throw new Error('Call not successful') diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index ccc0f628d..c9acbace3 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -178,7 +178,7 @@ export class TransactionLinkResolver { logger.info('redeem contribution link...') const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() - await queryRunner.startTransaction('SERIALIZABLE') + await queryRunner.startTransaction('REPEATABLE READ') try { const contributionLink = await queryRunner.manager .createQueryBuilder() @@ -283,7 +283,10 @@ export class TransactionLinkResolver { return true } else { const transactionLink = await dbTransactionLink.findOneOrFail({ code }) - const linkedUser = await dbUser.findOneOrFail({ id: transactionLink.userId }) + const linkedUser = await dbUser.findOneOrFail( + { id: transactionLink.userId }, + { relations: ['emailContact'] }, + ) if (user.id === linkedUser.id) { throw new Error('Cannot redeem own transaction link.') diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index bc062a1f4..b00d84de6 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -35,6 +35,8 @@ import Decimal from 'decimal.js-light' import { BalanceResolver } from './BalanceResolver' import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' +import { findUserByEmail } from './UserResolver' +import { sendTransactionLinkRedeemedEmail } from '@/mailer/sendTransactionLinkRedeemed' export const executeTransaction = async ( amount: Decimal, @@ -78,7 +80,7 @@ export const executeTransaction = async ( const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() - await queryRunner.startTransaction('READ UNCOMMITTED') + await queryRunner.startTransaction('REPEATABLE READ') logger.debug(`open Transaction to write...`) try { // transaction @@ -148,12 +150,24 @@ export const executeTransaction = async ( senderLastName: sender.lastName, recipientFirstName: recipient.firstName, recipientLastName: recipient.lastName, - email: recipient.email, - senderEmail: sender.email, + email: recipient.emailContact.email, + senderEmail: sender.emailContact.email, amount, - memo, overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, }) + if (transactionLink) { + await sendTransactionLinkRedeemedEmail({ + senderFirstName: recipient.firstName, + senderLastName: recipient.lastName, + recipientFirstName: sender.firstName, + recipientLastName: sender.lastName, + email: sender.emailContact.email, + senderEmail: recipient.emailContact.email, + amount, + memo, + overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, + }) + } logger.info(`finished executeTransaction successfully`) return true } @@ -171,7 +185,7 @@ export class TransactionResolver { const user = getUser(context) logger.addContext('user', user.id) - logger.info(`transactionList(user=${user.firstName}.${user.lastName}, ${user.email})`) + logger.info(`transactionList(user=${user.firstName}.${user.lastName}, ${user.emailId})`) // find current balance const lastTransaction = await dbTransaction.findOne( @@ -293,16 +307,25 @@ export class TransactionResolver { } // validate recipient user - const recipientUser = await dbUser.findOne({ email: email }, { withDeleted: true }) + const recipientUser = await findUserByEmail(email) + /* + const emailContact = await UserContact.findOne({ email }, { withDeleted: true }) + if (!emailContact) { + logger.error(`Could not find UserContact with email: ${email}`) + throw new Error(`Could not find UserContact with email: ${email}`) + } + */ + // const recipientUser = await dbUser.findOne({ id: emailContact.userId }) if (!recipientUser) { - logger.error(`recipient not known: email=${email}`) - throw new Error('recipient not known') + logger.error(`unknown recipient to UserContact: email=${email}`) + throw new Error('unknown recipient') } if (recipientUser.deletedAt) { logger.error(`The recipient account was deleted: recipientUser=${recipientUser}`) throw new Error('The recipient account was deleted') } - if (!recipientUser.emailChecked) { + const emailContact = recipientUser.emailContact + if (!emailContact.emailChecked) { logger.error(`The recipient account is not activated: recipientUser=${recipientUser}`) throw new Error('The recipient account is not activated') } diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 36bae56de..53dc392ba 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1,13 +1,19 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { testEnvironment, headerPushMock, resetToken, cleanDB, resetEntity } from '@test/helpers' +import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { createUser, setPassword, forgotPassword, updateUserInfos } from '@/seeds/graphql/mutations' +import { + createUser, + setPassword, + forgotPassword, + updateUserInfos, + createContribution, + confirmContribution, +} from '@/seeds/graphql/mutations' import { login, logout, verifyLogin, queryOptIn, searchAdminUsers } from '@/seeds/graphql/queries' import { GraphQLError } from 'graphql' -import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User } from '@entity/User' import CONFIG from '@/config' import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' @@ -15,13 +21,19 @@ import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegi import { sendResetPasswordEmail } from '@/mailer/sendResetPasswordEmail' import { printTimeDuration, activationLink } from './UserResolver' import { contributionLinkFactory } from '@/seeds/factory/contributionLink' -// import { transactionLinkFactory } from '@/seeds/factory/transactionLink' +import { transactionLinkFactory } from '@/seeds/factory/transactionLink' import { ContributionLink } from '@model/ContributionLink' -// import { TransactionLink } from '@entity/TransactionLink' +import { TransactionLink } from '@entity/TransactionLink' +import { EventProtocolType } from '@/event/EventProtocolType' +import { EventProtocol } from '@entity/EventProtocol' import { logger } from '@test/testSetup' import { validate as validateUUID, version as versionUUID } from 'uuid' import { peterLustig } from '@/seeds/users/peter-lustig' +import { UserContact } from '@entity/UserContact' +import { OptInType } from '../enum/OptInType' +import { UserContactType } from '../enum/UserContactType' +import { bobBaumeister } from '@/seeds/users/bob-baumeister' // import { klicktippSignIn } from '@/apis/KlicktippController' @@ -82,7 +94,7 @@ describe('UserResolver', () => { } let result: any - let emailOptIn: string + let emailVerificationCode: string let user: User[] beforeAll(async () => { @@ -101,11 +113,11 @@ describe('UserResolver', () => { }) describe('valid input data', () => { - let loginEmailOptIn: LoginEmailOptIn[] + // let loginEmailOptIn: LoginEmailOptIn[] beforeAll(async () => { - user = await User.find() - loginEmailOptIn = await LoginEmailOptIn.find() - emailOptIn = loginEmailOptIn[0].verificationCode.toString() + user = await User.find({ relations: ['emailContact'] }) + // loginEmailOptIn = await LoginEmailOptIn.find() + emailVerificationCode = user[0].emailContact.emailVerificationCode.toString() }) describe('filling all tables', () => { @@ -115,15 +127,16 @@ describe('UserResolver', () => { id: expect.any(Number), gradidoID: expect.any(String), alias: null, - email: 'peter@lustig.de', + emailContact: expect.any(UserContact), // 'peter@lustig.de', + emailId: expect.any(Number), firstName: 'Peter', lastName: 'Lustig', password: '0', pubKey: null, privKey: null, - emailHash: expect.any(Buffer), + // emailHash: expect.any(Buffer), createdAt: expect.any(Date), - emailChecked: false, + // emailChecked: false, passphrase: expect.any(String), language: 'de', isAdmin: null, @@ -139,18 +152,21 @@ describe('UserResolver', () => { expect(verUUID).toEqual(4) }) - it('creates an email optin', () => { - expect(loginEmailOptIn).toEqual([ - { - id: expect.any(Number), - userId: user[0].id, - verificationCode: expect.any(String), - emailOptInTypeId: 1, - createdAt: expect.any(Date), - resendCount: 0, - updatedAt: expect.any(Date), - }, - ]) + it('creates an email contact', () => { + expect(user[0].emailContact).toEqual({ + id: expect.any(Number), + type: UserContactType.USER_CONTACT_EMAIL, + userId: user[0].id, + email: 'peter@lustig.de', + emailChecked: false, + emailVerificationCode: expect.any(String), + emailOptInTypeId: OptInType.EMAIL_OPT_IN_REGISTER, + emailResendCount: 0, + phone: null, + createdAt: expect.any(Date), + deletedAt: null, + updatedAt: null, + }) }) }) }) @@ -159,7 +175,7 @@ describe('UserResolver', () => { it('sends an account activation email', () => { const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace( /{optin}/g, - emailOptIn, + emailVerificationCode, ).replace(/{code}/g, '') expect(sendAccountActivationEmail).toBeCalledWith({ link: activationLink, @@ -169,6 +185,15 @@ describe('UserResolver', () => { duration: expect.any(String), }) }) + + it('stores the send confirmation event in the database', () => { + expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.SEND_CONFIRMATION_EMAIL, + userId: user[0].id, + }), + ) + }) }) describe('email already exists', () => { @@ -208,13 +233,13 @@ describe('UserResolver', () => { mutation: createUser, variables: { ...variables, email: 'bibi@bloxberg.de', language: 'it' }, }) - await expect(User.find()).resolves.toEqual( - expect.arrayContaining([ - expect.objectContaining({ - email: 'bibi@bloxberg.de', - language: 'de', - }), - ]), + await expect( + UserContact.findOne({ email: 'bibi@bloxberg.de' }, { relations: ['user'] }), + ).resolves.toEqual( + expect.objectContaining({ + email: 'bibi@bloxberg.de', + user: expect.objectContaining({ language: 'de' }), + }), ) }) }) @@ -225,10 +250,12 @@ describe('UserResolver', () => { mutation: createUser, variables: { ...variables, email: 'raeuber@hotzenplotz.de', publisherId: undefined }, }) - await expect(User.find()).resolves.toEqual( + await expect(User.find({ relations: ['emailContact'] })).resolves.toEqual( expect.arrayContaining([ expect.objectContaining({ - email: 'raeuber@hotzenplotz.de', + emailContact: expect.objectContaining({ + email: 'raeuber@hotzenplotz.de', + }), publisherId: null, }), ]), @@ -237,37 +264,157 @@ describe('UserResolver', () => { }) describe('redeem codes', () => { + let result: any + let link: ContributionLink + describe('contribution link', () => { - let link: ContributionLink beforeAll(async () => { // activate account of admin Peter Lustig await mutate({ mutation: setPassword, - variables: { code: emailOptIn, password: 'Aa12345_' }, + variables: { code: emailVerificationCode, password: 'Aa12345_' }, }) + // make Peter Lustig Admin const peter = await User.findOneOrFail({ id: user[0].id }) peter.isAdmin = new Date() await peter.save() + + // date statement + const actualDate = new Date() + const futureDate = new Date() // Create a future day from the executed day + futureDate.setDate(futureDate.getDate() + 1) + // factory logs in as Peter Lustig link = await contributionLinkFactory(testEnv, { name: 'Dokumenta 2022', memo: 'Vielen Dank für deinen Besuch bei der Dokumenta 2022', amount: 200, - validFrom: new Date(2022, 5, 18), - validTo: new Date(2022, 8, 25), + validFrom: actualDate, + validTo: futureDate, }) + resetToken() - await mutate({ + result = await mutate({ mutation: createUser, variables: { ...variables, email: 'ein@besucher.de', redeemCode: 'CL-' + link.code }, }) }) + afterAll(async () => { + await cleanDB() + }) + it('sets the contribution link id', async () => { - await expect(User.findOne({ email: 'ein@besucher.de' })).resolves.toEqual( + await expect( + UserContact.findOne({ email: 'ein@besucher.de' }, { relations: ['user'] }), + ).resolves.toEqual( expect.objectContaining({ - contributionLinkId: link.id, + user: expect.objectContaining({ + contributionLinkId: link.id, + }), + }), + ) + }) + + it('stores the account activated event in the database', () => { + expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.ACTIVATE_ACCOUNT, + userId: user[0].id, + }), + ) + }) + + it('stores the redeem register event in the database', () => { + expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.REDEEM_REGISTER, + userId: result.data.createUser.id, + contributionId: link.id, + }), + ) + }) + }) + + describe('transaction link', () => { + let contribution: any + let bob: any + let transactionLink: TransactionLink + let newUser: any + + const bobData = { + email: 'bob@baumeister.de', + password: 'Aa12345_', + publisherId: 1234, + } + + const peterData = { + email: 'peter@lustig.de', + password: 'Aa12345_', + publisherId: 1234, + } + + beforeAll(async () => { + await userFactory(testEnv, peterLustig) + await userFactory(testEnv, bobBaumeister) + await query({ query: login, variables: bobData }) + + // create contribution as user bob + contribution = await mutate({ + mutation: createContribution, + variables: { amount: 1000, memo: 'testing', creationDate: new Date().toISOString() }, + }) + + // login as admin + await query({ query: login, variables: peterData }) + + // confirm the contribution + contribution = await mutate({ + mutation: confirmContribution, + variables: { id: contribution.data.createContribution.id }, + }) + + // login as user bob + bob = await query({ query: login, variables: bobData }) + + // create transaction link + await transactionLinkFactory(testEnv, { + email: 'bob@baumeister.de', + amount: 19.99, + memo: `testing transaction link`, + }) + + transactionLink = await TransactionLink.findOneOrFail() + + resetToken() + + // create new user using transaction link of bob + newUser = await mutate({ + mutation: createUser, + variables: { + ...variables, + email: 'which@ever.de', + redeemCode: transactionLink.code, + }, + }) + }) + + it('sets the referrer id to bob baumeister id', async () => { + await expect( + UserContact.findOne({ email: 'which@ever.de' }, { relations: ['user'] }), + ).resolves.toEqual( + expect.objectContaining({ + user: expect.objectContaining({ referrerId: bob.data.login.id }), + }), + ) + }) + + it('stores the redeem register event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.REDEEM_REGISTER, + userId: newUser.data.createUser.id, }), ) }) @@ -282,7 +429,7 @@ describe('UserResolver', () => { email: 'peter@lustig.de', amount: 19.99, memo: `Kein Trick, keine Zauberrei, -bei Gradidio sei dabei!`, + bei Gradidio sei dabei!`, }) const transactionLink = await TransactionLink.findOneOrFail() resetToken() @@ -291,14 +438,14 @@ bei Gradidio sei dabei!`, variables: { ...variables, email: 'neuer@user.de', redeemCode: transactionLink.code }, }) }) - + it('sets the referrer id to Peter Lustigs id', async () => { await expect(User.findOne({ email: 'neuer@user.de' })).resolves.toEqual(expect.objectContaining({ referrerId: user[0].id, })) }) }) - + */ }) }) @@ -313,20 +460,23 @@ bei Gradidio sei dabei!`, } let result: any - let emailOptIn: string + let emailVerificationCode: string describe('valid optin code and valid password', () => { - let newUser: any + let newUser: User beforeAll(async () => { await mutate({ mutation: createUser, variables: createUserVariables }) - const loginEmailOptIn = await LoginEmailOptIn.find() - emailOptIn = loginEmailOptIn[0].verificationCode.toString() + const emailContact = await UserContact.findOneOrFail({ email: createUserVariables.email }) + emailVerificationCode = emailContact.emailVerificationCode.toString() result = await mutate({ mutation: setPassword, - variables: { code: emailOptIn, password: 'Aa12345_' }, + variables: { code: emailVerificationCode, password: 'Aa12345_' }, }) - newUser = await User.find() + newUser = await User.findOneOrFail( + { id: emailContact.userId }, + { relations: ['emailContact'] }, + ) }) afterAll(async () => { @@ -334,11 +484,11 @@ bei Gradidio sei dabei!`, }) it('sets email checked to true', () => { - expect(newUser[0].emailChecked).toBeTruthy() + expect(newUser.emailContact.emailChecked).toBeTruthy() }) it('updates the password', () => { - expect(newUser[0].password).toEqual('3917921995996627700') + expect(newUser.password).toEqual('3917921995996627700') }) /* @@ -360,11 +510,11 @@ bei Gradidio sei dabei!`, describe('no valid password', () => { beforeAll(async () => { await mutate({ mutation: createUser, variables: createUserVariables }) - const loginEmailOptIn = await LoginEmailOptIn.find() - emailOptIn = loginEmailOptIn[0].verificationCode.toString() + const emailContact = await UserContact.findOneOrFail({ email: createUserVariables.email }) + emailVerificationCode = emailContact.emailVerificationCode.toString() result = await mutate({ mutation: setPassword, - variables: { code: emailOptIn, password: 'not-valid' }, + variables: { code: emailVerificationCode, password: 'not-valid' }, }) }) @@ -383,6 +533,10 @@ bei Gradidio sei dabei!`, }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Password entered is lexically invalid') + }) }) describe('no valid optin code', () => { @@ -405,6 +559,10 @@ bei Gradidio sei dabei!`, }), ) }) + + it('logs the error found', () => { + expect(logger.error).toBeCalledWith('Could not login with emailVerificationCode') + }) }) }) @@ -423,6 +581,7 @@ bei Gradidio sei dabei!`, describe('no users in database', () => { beforeAll(async () => { + jest.clearAllMocks() result = await query({ query: login, variables }) }) @@ -433,6 +592,12 @@ bei Gradidio sei dabei!`, }), ) }) + + it('logs the error found', () => { + expect(logger.error).toBeCalledWith( + 'UserContact with email=bibi@bloxberg.de does not exists', + ) + }) }) describe('user is in database and correct login data', () => { @@ -475,6 +640,7 @@ bei Gradidio sei dabei!`, describe('user is in database and wrong password', () => { beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) + result = await query({ query: login, variables: { ...variables, password: 'wrong' } }) }) afterAll(async () => { @@ -482,14 +648,16 @@ bei Gradidio sei dabei!`, }) it('returns an error', () => { - expect( - query({ query: login, variables: { ...variables, password: 'wrong' } }), - ).resolves.toEqual( + expect(result).toEqual( expect.objectContaining({ errors: [new GraphQLError('No user with this credentials')], }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('The User has no valid credentials.') + }) }) }) @@ -562,6 +730,8 @@ bei Gradidio sei dabei!`, }) describe('authenticated', () => { + let user: User[] + const variables = { email: 'bibi@bloxberg.de', password: 'Aa12345_', @@ -569,6 +739,7 @@ bei Gradidio sei dabei!`, beforeAll(async () => { await query({ query: login, variables }) + user = await User.find() }) afterAll(() => { @@ -595,52 +766,83 @@ bei Gradidio sei dabei!`, }), ) }) + + it('stores the login event in the database', () => { + expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.LOGIN, + userId: user[0].id, + }), + ) + }) }) }) }) describe('forgotPassword', () => { const variables = { email: 'bibi@bloxberg.de' } + const emailCodeRequestTime = CONFIG.EMAIL_CODE_REQUEST_TIME + describe('user is not in DB', () => { - it('returns true', async () => { - await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( - expect.objectContaining({ - data: { - forgotPassword: true, - }, - }), - ) + describe('duration not expired', () => { + it('returns true', async () => { + await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( + expect.objectContaining({ + data: { + forgotPassword: true, + }, + }), + ) + }) }) }) describe('user exists in DB', () => { - let result: any - let loginEmailOptIn: LoginEmailOptIn[] + let emailContact: UserContact beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) - await resetEntity(LoginEmailOptIn) - result = await mutate({ mutation: forgotPassword, variables }) - loginEmailOptIn = await LoginEmailOptIn.find() + // await resetEntity(LoginEmailOptIn) + emailContact = await UserContact.findOneOrFail(variables) }) afterAll(async () => { await cleanDB() + CONFIG.EMAIL_CODE_REQUEST_TIME = emailCodeRequestTime }) - it('returns true', async () => { - await expect(result).toEqual( - expect.objectContaining({ - data: { - forgotPassword: true, - }, - }), - ) + describe('duration not expired', () => { + it('returns true', async () => { + await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + `email already sent less than ${printTimeDuration( + CONFIG.EMAIL_CODE_REQUEST_TIME, + )} minutes ago`, + ), + ], + }), + ) + }) + }) + + describe('duration reset to 0', () => { + it('returns true', async () => { + CONFIG.EMAIL_CODE_REQUEST_TIME = 0 + await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( + expect.objectContaining({ + data: { + forgotPassword: true, + }, + }), + ) + }) }) it('sends reset password email', () => { expect(sendResetPasswordEmail).toBeCalledWith({ - link: activationLink(loginEmailOptIn[0]), + link: activationLink(emailContact.emailVerificationCode), firstName: 'Bibi', lastName: 'Bloxberg', email: 'bibi@bloxberg.de', @@ -650,22 +852,27 @@ bei Gradidio sei dabei!`, describe('request reset password again', () => { it('thows an error', async () => { + CONFIG.EMAIL_CODE_REQUEST_TIME = emailCodeRequestTime await expect(mutate({ mutation: forgotPassword, variables })).resolves.toEqual( expect.objectContaining({ errors: [new GraphQLError('email already sent less than 10 minutes minutes ago')], }), ) }) + + it('logs the error found', () => { + expect(logger.error).toBeCalledWith(`email already sent less than 10 minutes minutes ago`) + }) }) }) }) describe('queryOptIn', () => { - let loginEmailOptIn: LoginEmailOptIn[] + let emailContact: UserContact beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) - loginEmailOptIn = await LoginEmailOptIn.find() + emailContact = await UserContact.findOneOrFail({ email: bibiBloxberg.email }) }) afterAll(async () => { @@ -680,8 +887,8 @@ bei Gradidio sei dabei!`, expect.objectContaining({ errors: [ // keep Whitspace in error message! - new GraphQLError(`Could not find any entity of type "LoginEmailOptIn" matching: { - "verificationCode": "not-valid" + new GraphQLError(`Could not find any entity of type "UserContact" matching: { + "emailVerificationCode": "not-valid" }`), ], }), @@ -694,7 +901,7 @@ bei Gradidio sei dabei!`, await expect( query({ query: queryOptIn, - variables: { optIn: loginEmailOptIn[0].verificationCode.toString() }, + variables: { optIn: emailContact.emailVerificationCode.toString() }, }), ).resolves.toEqual( expect.objectContaining({ @@ -766,7 +973,7 @@ bei Gradidio sei dabei!`, }) describe('language is not valid', () => { - it('thows an error', async () => { + it('throws an error', async () => { await expect( mutate({ mutation: updateUserInfos, @@ -780,6 +987,10 @@ bei Gradidio sei dabei!`, }), ) }) + + it('logs the error found', () => { + expect(logger.error).toBeCalledWith(`"not-valid" isn't a valid language`) + }) }) describe('password', () => { @@ -799,6 +1010,10 @@ bei Gradidio sei dabei!`, }), ) }) + + it('logs the error found', () => { + expect(logger.error).toBeCalledWith(`Old password is invalid`) + }) }) describe('invalid new password', () => { @@ -821,6 +1036,10 @@ bei Gradidio sei dabei!`, }), ) }) + + it('logs the error found', () => { + expect(logger.error).toBeCalledWith('newPassword does not fullfil the rules') + }) }) describe('correct old and new password', () => { @@ -840,7 +1059,7 @@ bei Gradidio sei dabei!`, ) }) - it('can login wtih new password', async () => { + it('can login with new password', async () => { await expect( query({ query: login, @@ -860,7 +1079,7 @@ bei Gradidio sei dabei!`, ) }) - it('cannot login wtih old password', async () => { + it('cannot login with old password', async () => { await expect( query({ query: login, @@ -875,6 +1094,10 @@ bei Gradidio sei dabei!`, }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('The User has no valid credentials.') + }) }) }) }) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 3b7013323..5ad578767 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -1,12 +1,12 @@ import fs from 'fs' import { backendLogger as logger } from '@/server/logger' - import { Context, getUser } from '@/server/context' import { Resolver, Query, Args, Arg, Authorized, Ctx, UseMiddleware, Mutation } from 'type-graphql' import { getConnection, getCustomRepository, IsNull, Not } from '@dbTools/typeorm' import CONFIG from '@/config' import { User } from '@model/User' import { User as DbUser } from '@entity/User' +import { UserContact as DbUserContact } from '@entity/UserContact' import { communityDbUser } from '@/util/communityUser' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { ContributionLink as dbContributionLink } from '@entity/ContributionLink' @@ -16,7 +16,6 @@ import UnsecureLoginArgs from '@arg/UnsecureLoginArgs' import UpdateUserInfosArgs from '@arg/UpdateUserInfosArgs' import { klicktippNewsletterStateMiddleware } from '@/middleware/klicktippMiddleware' import { OptInType } from '@enum/OptInType' -import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { sendResetPasswordEmail as sendResetPasswordEmailMailer } from '@/mailer/sendResetPasswordEmail' import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegistrationEmail' @@ -29,9 +28,12 @@ import { EventLogin, EventRedeemRegister, EventRegister, + EventSendAccountMultiRegistrationEmail, EventSendConfirmationEmail, + EventActivateAccount, } from '@/event/Event' import { getUserCreation } from './util/creations' +import { UserContactType } from '../enum/UserContactType' import { UserRepository } from '@/typeorm/repository/User' import { SearchAdminUsersResult } from '@model/AdminUser' import Paginated from '@arg/Paginated' @@ -146,6 +148,7 @@ const SecretKeyCryptographyCreateKey = (salt: string, password: string): Buffer[ return [encryptionKeyHash, encryptionKey] } +/* const getEmailHash = (email: string): Buffer => { logger.trace('getEmailHash...') const emailHash = Buffer.alloc(sodium.crypto_generichash_BYTES) @@ -153,6 +156,7 @@ const getEmailHash = (email: string): Buffer => { logger.debug(`getEmailHash...successful: ${emailHash}`) return emailHash } +*/ const SecretKeyCryptographyEncrypt = (message: Buffer, encryptionKey: Buffer): Buffer => { logger.trace('SecretKeyCryptographyEncrypt...') @@ -177,6 +181,19 @@ const SecretKeyCryptographyDecrypt = (encryptedMessage: Buffer, encryptionKey: B return message } +const newEmailContact = (email: string, userId: number): DbUserContact => { + logger.trace(`newEmailContact...`) + const emailContact = new DbUserContact() + emailContact.email = email + emailContact.userId = userId + emailContact.type = UserContactType.USER_CONTACT_EMAIL + emailContact.emailChecked = false + emailContact.emailOptInTypeId = OptInType.EMAIL_OPT_IN_REGISTER + emailContact.emailVerificationCode = random(64) + logger.debug(`newEmailContact...successful: ${emailContact}`) + return emailContact +} +/* const newEmailOptIn = (userId: number): LoginEmailOptIn => { logger.trace('newEmailOptIn...') const emailOptIn = new LoginEmailOptIn() @@ -186,7 +203,8 @@ const newEmailOptIn = (userId: number): LoginEmailOptIn => { logger.debug(`newEmailOptIn...successful: ${emailOptIn}`) return emailOptIn } - +*/ +/* // needed by AdminResolver // checks if given code exists and can be resent // if optIn does not exits, it is created @@ -226,10 +244,44 @@ export const checkOptInCode = async ( logger.debug(`checkOptInCode...successful: ${optInCode} for userid=${user.id}`) return optInCode } +*/ +export const checkEmailVerificationCode = async ( + emailContact: DbUserContact, + optInType: OptInType = OptInType.EMAIL_OPT_IN_REGISTER, +): Promise => { + logger.info(`checkEmailVerificationCode... ${emailContact}`) + if (emailContact.updatedAt) { + if (!canEmailResend(emailContact.updatedAt)) { + logger.error( + `email already sent less than ${printTimeDuration( + CONFIG.EMAIL_CODE_REQUEST_TIME, + )} minutes ago`, + ) + throw new Error( + `email already sent less than ${printTimeDuration( + CONFIG.EMAIL_CODE_REQUEST_TIME, + )} minutes ago`, + ) + } + emailContact.updatedAt = new Date() + emailContact.emailResendCount++ + } else { + logger.trace('create new EmailVerificationCode for userId=' + emailContact.userId) + emailContact.emailChecked = false + emailContact.emailVerificationCode = random(64) + } + emailContact.emailOptInTypeId = optInType + await DbUserContact.save(emailContact).catch(() => { + logger.error('Unable to save email verification code= ' + emailContact) + throw new Error('Unable to save email verification code.') + }) + logger.debug(`checkEmailVerificationCode...successful: ${emailContact}`) + return emailContact +} -export const activationLink = (optInCode: LoginEmailOptIn): string => { - logger.debug(`activationLink(${LoginEmailOptIn})...`) - return CONFIG.EMAIL_LINK_SETPASSWORD.replace(/{optin}/g, optInCode.verificationCode.toString()) +export const activationLink = (verificationCode: BigInt): string => { + logger.debug(`activationLink(${verificationCode})...`) + return CONFIG.EMAIL_LINK_SETPASSWORD.replace(/{optin}/g, verificationCode.toString()) } const newGradidoID = async (): Promise => { @@ -272,15 +324,12 @@ export class UserResolver { ): Promise { logger.info(`login with ${email}, ***, ${publisherId} ...`) email = email.trim().toLowerCase() - const dbUser = await DbUser.findOneOrFail({ email }, { withDeleted: true }).catch(() => { - logger.error(`User with email=${email} does not exists`) - throw new Error('No user with this credentials') - }) + const dbUser = await findUserByEmail(email) if (dbUser.deletedAt) { logger.error('The User was permanently deleted in database.') throw new Error('This user was permanently deleted. Contact support for questions.') } - if (!dbUser.emailChecked) { + if (!dbUser.emailContact.emailChecked) { logger.error('The Users email is not validate yet.') throw new Error('User email not validated') } @@ -305,7 +354,7 @@ export class UserResolver { logger.debug('login credentials valid...') const user = new User(dbUser, await getUserCreation(dbUser.id)) - logger.debug('user=' + user) + logger.debug(`user= ${JSON.stringify(user, null, 2)}`) // Elopage Status & Stored PublisherId user.hasElopage = await this.hasElopage({ ...context, user: dbUser }) @@ -323,7 +372,7 @@ export class UserResolver { const ev = new EventLogin() ev.userId = user.id eventProtocol.writeEvent(new Event().setEventLogin(ev)) - logger.info('successful Login:' + user) + logger.info(`successful Login: ${JSON.stringify(user, null, 2)}`) return user } @@ -352,66 +401,72 @@ export class UserResolver { ) // TODO: wrong default value (should be null), how does graphql work here? Is it an required field? // default int publisher_id = 0; + const event = new Event() // Validate Language (no throw) if (!language || !isLanguage(language)) { language = DEFAULT_LANGUAGE } - // Validate email unique + // check if user with email still exists? email = email.trim().toLowerCase() - // TODO we cannot use repository.count(), since it does not allow to specify if you want to include the soft deletes - const userFound = await DbUser.findOne({ email }, { withDeleted: true }) - logger.info(`DbUser.findOne(email=${email}) = ${userFound}`) + if (await checkEmailExists(email)) { + const foundUser = await findUserByEmail(email) + logger.info(`DbUser.findOne(email=${email}) = ${foundUser}`) - if (userFound) { - // ATTENTION: this logger-message will be exactly expected during tests - logger.info(`User already exists with this email=${email}`) - // TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent. + if (foundUser) { + // ATTENTION: this logger-message will be exactly expected during tests + logger.info(`User already exists with this email=${email}`) + // TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent. - const user = new User(communityDbUser) - user.id = sodium.randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in? - user.gradidoID = uuidv4() - user.email = email - user.firstName = firstName - user.lastName = lastName - user.language = language - user.publisherId = publisherId - logger.debug('partly faked user=' + user) + const user = new User(communityDbUser) + user.id = sodium.randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in? + user.gradidoID = uuidv4() + user.email = email + user.firstName = firstName + user.lastName = lastName + user.language = language + user.publisherId = publisherId + logger.debug('partly faked user=' + user) - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const emailSent = await sendAccountMultiRegistrationEmail({ - firstName, - lastName, - email, - }) - logger.info(`sendAccountMultiRegistrationEmail of ${firstName}.${lastName} to ${email}`) - /* uncomment this, when you need the activation link on the console */ - // In case EMails are disabled log the activation link for the user - if (!emailSent) { - logger.debug(`Email not send!`) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const emailSent = await sendAccountMultiRegistrationEmail({ + firstName, + lastName, + email, + }) + const eventSendAccountMultiRegistrationEmail = new EventSendAccountMultiRegistrationEmail() + eventSendAccountMultiRegistrationEmail.userId = foundUser.id + eventProtocol.writeEvent( + event.setEventSendConfirmationEmail(eventSendAccountMultiRegistrationEmail), + ) + logger.info(`sendAccountMultiRegistrationEmail of ${firstName}.${lastName} to ${email}`) + /* uncomment this, when you need the activation link on the console */ + // In case EMails are disabled log the activation link for the user + if (!emailSent) { + logger.debug(`Email not send!`) + } + logger.info('createUser() faked and send multi registration mail...') + + return user } - logger.info('createUser() faked and send multi registration mail...') - - return user } const passphrase = PassphraseGenerate() // const keyPair = KeyPairEd25519Create(passphrase) // return pub, priv Key // const passwordHash = SecretKeyCryptographyCreateKey(email, password) // return short and long hash // const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) - const emailHash = getEmailHash(email) + // const emailHash = getEmailHash(email) const gradidoID = await newGradidoID() const eventRegister = new EventRegister() const eventRedeemRegister = new EventRedeemRegister() const eventSendConfirmEmail = new EventSendConfirmationEmail() - const dbUser = new DbUser() + + let dbUser = new DbUser() dbUser.gradidoID = gradidoID - dbUser.email = email dbUser.firstName = firstName dbUser.lastName = lastName - dbUser.emailHash = emailHash dbUser.language = language dbUser.publisherId = publisherId dbUser.passphrase = passphrase.join(' ') @@ -442,25 +497,38 @@ export class UserResolver { // loginUser.pubKey = keyPair[0] // loginUser.privKey = encryptedPrivkey - const event = new Event() const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() - await queryRunner.startTransaction('READ UNCOMMITTED') + await queryRunner.startTransaction('REPEATABLE READ') try { - await queryRunner.manager.save(dbUser).catch((error) => { + dbUser = await queryRunner.manager.save(dbUser).catch((error) => { logger.error('Error while saving dbUser', error) throw new Error('error saving user') }) + let emailContact = newEmailContact(email, dbUser.id) + emailContact = await queryRunner.manager.save(emailContact).catch((error) => { + logger.error('Error while saving emailContact', error) + throw new Error('error saving email user contact') + }) + dbUser.emailContact = emailContact + dbUser.emailId = emailContact.id + await queryRunner.manager.save(dbUser).catch((error) => { + logger.error('Error while updating dbUser', error) + throw new Error('error updating user') + }) + + /* const emailOptIn = newEmailOptIn(dbUser.id) await queryRunner.manager.save(emailOptIn).catch((error) => { logger.error('Error while saving emailOptIn', error) throw new Error('error saving email opt in') }) + */ const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace( /{optin}/g, - emailOptIn.verificationCode.toString(), + emailContact.emailVerificationCode.toString(), ).replace(/{code}/g, redeemCode ? '/' + redeemCode : '') // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -475,8 +543,6 @@ export class UserResolver { eventSendConfirmEmail.userId = dbUser.id eventProtocol.writeEvent(event.setEventSendConfirmationEmail(eventSendConfirmEmail)) - /* uncomment this, when you need the activation link on the console */ - // In case EMails are disabled log the activation link for the user if (!emailSent) { logger.debug(`Account confirmation link: ${activationLink}`) } @@ -493,10 +559,10 @@ export class UserResolver { if (redeemCode) { eventRedeemRegister.userId = dbUser.id - eventProtocol.writeEvent(event.setEventRedeemRegister(eventRedeemRegister)) + await eventProtocol.writeEvent(event.setEventRedeemRegister(eventRedeemRegister)) } else { eventRegister.userId = dbUser.id - eventProtocol.writeEvent(event.setEventRegister(eventRegister)) + await eventProtocol.writeEvent(event.setEventRegister(eventRegister)) } return new User(dbUser) @@ -507,22 +573,29 @@ export class UserResolver { async forgotPassword(@Arg('email') email: string): Promise { logger.info(`forgotPassword(${email})...`) email = email.trim().toLowerCase() - const user = await DbUser.findOne({ email }) + const user = await findUserByEmail(email).catch(() => { + logger.warn(`fail on find UserContact per ${email}`) + }) if (!user) { logger.warn(`no user found with ${email}`) return true } // can be both types: REGISTER and RESET_PASSWORD - let optInCode = await LoginEmailOptIn.findOne({ - userId: user.id, - }) + // let optInCode = await LoginEmailOptIn.findOne({ + // userId: user.id, + // }) + // let optInCode = user.emailContact.emailVerificationCode + const dbUserContact = await checkEmailVerificationCode( + user.emailContact, + OptInType.EMAIL_OPT_IN_RESET_PASSWORD, + ) - optInCode = await checkOptInCode(optInCode, user, OptInType.EMAIL_OPT_IN_RESET_PASSWORD) - logger.info(`optInCode for ${email}=${optInCode}`) + // optInCode = await checkOptInCode(optInCode, user, OptInType.EMAIL_OPT_IN_RESET_PASSWORD) + logger.info(`optInCode for ${email}=${dbUserContact}`) // eslint-disable-next-line @typescript-eslint/no-unused-vars const emailSent = await sendResetPasswordEmailMailer({ - link: activationLink(optInCode), + link: activationLink(dbUserContact.emailVerificationCode), firstName: user.firstName, lastName: user.lastName, email, @@ -532,7 +605,7 @@ export class UserResolver { /* uncomment this, when you need the activation link on the console */ // In case EMails are disabled log the activation link for the user if (!emailSent) { - logger.debug(`Reset password link: ${activationLink(optInCode)}`) + logger.debug(`Reset password link: ${activationLink(dbUserContact.emailVerificationCode)}`) } logger.info(`forgotPassword(${email}) successful...`) @@ -548,19 +621,29 @@ export class UserResolver { logger.info(`setPassword(${code}, ***)...`) // Validate Password if (!isPassword(password)) { + logger.error('Password entered is lexically invalid') throw new Error( 'Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character!', ) } // Load code + /* const optInCode = await LoginEmailOptIn.findOneOrFail({ verificationCode: code }).catch(() => { logger.error('Could not login with emailVerificationCode') throw new Error('Could not login with emailVerificationCode') }) - logger.debug('optInCode loaded...') + */ + const userContact = await DbUserContact.findOneOrFail( + { emailVerificationCode: code }, + { relations: ['user'] }, + ).catch(() => { + logger.error('Could not login with emailVerificationCode') + throw new Error('Could not login with emailVerificationCode') + }) + logger.debug('userContact loaded...') // Code is only valid for `CONFIG.EMAIL_CODE_VALID_TIME` minutes - if (!isOptInValid(optInCode)) { + if (!isEmailVerificationCodeValid(userContact.updatedAt)) { logger.error( `email was sent more than ${printTimeDuration(CONFIG.EMAIL_CODE_VALID_TIME)} ago`, ) @@ -568,14 +651,11 @@ export class UserResolver { `email was sent more than ${printTimeDuration(CONFIG.EMAIL_CODE_VALID_TIME)} ago`, ) } - logger.debug('optInCode is valid...') + logger.debug('EmailVerificationCode is valid...') // load user - const user = await DbUser.findOneOrFail({ id: optInCode.userId }).catch(() => { - logger.error('Could not find corresponding Login User') - throw new Error('Could not find corresponding Login User') - }) - logger.debug('user with optInCode found...') + const user = userContact.user + logger.debug('user with EmailVerificationCode found...') // Generate Passphrase if needed if (!user.passphrase) { @@ -595,10 +675,10 @@ export class UserResolver { logger.debug('Passphrase is valid...') // Activate EMail - user.emailChecked = true + userContact.emailChecked = true // Update Password - const passwordHash = SecretKeyCryptographyCreateKey(user.email, password) // return short and long hash + const passwordHash = SecretKeyCryptographyCreateKey(userContact.email, password) // return short and long hash const keyPair = KeyPairEd25519Create(passphrase) // return pub, priv Key const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) user.password = passwordHash[0].readBigUInt64LE() // using the shorthash @@ -608,7 +688,9 @@ export class UserResolver { const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() - await queryRunner.startTransaction('READ UNCOMMITTED') + await queryRunner.startTransaction('REPEATABLE READ') + + const event = new Event() try { // Save user @@ -616,12 +698,21 @@ export class UserResolver { logger.error('error saving user: ' + error) throw new Error('error saving user: ' + error) }) + // Save userContact + await queryRunner.manager.save(userContact).catch((error) => { + logger.error('error saving userContact: ' + error) + throw new Error('error saving userContact: ' + error) + }) await queryRunner.commitTransaction() - logger.info('User data written successfully...') + logger.info('User and UserContact data written successfully...') + + const eventActivateAccount = new EventActivateAccount() + eventActivateAccount.userId = user.id + eventProtocol.writeEvent(event.setEventActivateAccount(eventActivateAccount)) } catch (e) { await queryRunner.rollbackTransaction() - logger.error('Error on writing User data:' + e) + logger.error('Error on writing User and UserContact data:' + e) throw e } finally { await queryRunner.release() @@ -629,11 +720,11 @@ export class UserResolver { // Sign into Klicktipp // TODO do we always signUp the user? How to handle things with old users? - if (optInCode.emailOptInTypeId === OptInType.EMAIL_OPT_IN_REGISTER) { + if (userContact.emailOptInTypeId === OptInType.EMAIL_OPT_IN_REGISTER) { try { - await klicktippSignIn(user.email, user.language, user.firstName, user.lastName) + await klicktippSignIn(userContact.email, user.language, user.firstName, user.lastName) logger.debug( - `klicktippSignIn(${user.email}, ${user.language}, ${user.firstName}, ${user.lastName})`, + `klicktippSignIn(${userContact.email}, ${user.language}, ${user.firstName}, ${user.lastName})`, ) } catch (e) { logger.error('Error subscribe to klicktipp:' + e) @@ -652,10 +743,10 @@ export class UserResolver { @Query(() => Boolean) async queryOptIn(@Arg('optIn') optIn: string): Promise { logger.info(`queryOptIn(${optIn})...`) - const optInCode = await LoginEmailOptIn.findOneOrFail({ verificationCode: optIn }) - logger.debug(`found optInCode=${optInCode}`) + const userContact = await DbUserContact.findOneOrFail({ emailVerificationCode: optIn }) + logger.debug(`found optInCode=${userContact}`) // Code is only valid for `CONFIG.EMAIL_CODE_VALID_TIME` minutes - if (!isOptInValid(optInCode)) { + if (!isEmailVerificationCodeValid(userContact.updatedAt)) { logger.error( `email was sent more than ${printTimeDuration(CONFIG.EMAIL_CODE_VALID_TIME)} ago`, ) @@ -703,7 +794,10 @@ export class UserResolver { } // TODO: This had some error cases defined - like missing private key. This is no longer checked. - const oldPasswordHash = SecretKeyCryptographyCreateKey(userEntity.email, password) + const oldPasswordHash = SecretKeyCryptographyCreateKey( + userEntity.emailContact.email, + password, + ) if (BigInt(userEntity.password.toString()) !== oldPasswordHash[0].readBigUInt64LE()) { logger.error(`Old password is invalid`) throw new Error(`Old password is invalid`) @@ -711,7 +805,10 @@ export class UserResolver { const privKey = SecretKeyCryptographyDecrypt(userEntity.privKey, oldPasswordHash[1]) logger.debug('oldPassword decrypted...') - const newPasswordHash = SecretKeyCryptographyCreateKey(userEntity.email, passwordNew) // return short and long hash + const newPasswordHash = SecretKeyCryptographyCreateKey( + userEntity.emailContact.email, + passwordNew, + ) // return short and long hash logger.debug('newPasswordHash created...') const encryptedPrivkey = SecretKeyCryptographyEncrypt(privKey, newPasswordHash[1]) logger.debug('PrivateKey encrypted...') @@ -723,10 +820,11 @@ export class UserResolver { const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() - await queryRunner.startTransaction('READ UNCOMMITTED') + await queryRunner.startTransaction('REPEATABLE READ') try { await queryRunner.manager.save(userEntity).catch((error) => { + logger.error('error saving user: ' + error) throw new Error('error saving user: ' + error) }) @@ -747,12 +845,8 @@ export class UserResolver { @Query(() => Boolean) async hasElopage(@Ctx() context: Context): Promise { logger.info(`hasElopage()...`) - const userEntity = context.user - if (!userEntity) { - logger.info('missing context.user for EloPage-check') - return false - } - const elopageBuys = hasElopageBuys(userEntity.email) + const userEntity = getUser(context) + const elopageBuys = hasElopageBuys(userEntity.emailContact.email) logger.debug(`has ElopageBuys = ${elopageBuys}`) return elopageBuys } @@ -788,19 +882,58 @@ export class UserResolver { } } +export async function findUserByEmail(email: string): Promise { + const dbUserContact = await DbUserContact.findOneOrFail( + { email: email }, + { withDeleted: true, relations: ['user'] }, + ).catch(() => { + logger.error(`UserContact with email=${email} does not exists`) + throw new Error('No user with this credentials') + }) + const dbUser = dbUserContact.user + dbUser.emailContact = dbUserContact + return dbUser +} + +async function checkEmailExists(email: string): Promise { + const userContact = await DbUserContact.findOne({ email: email }, { withDeleted: true }) + if (userContact) { + return true + } + return false +} + +/* const isTimeExpired = (optIn: LoginEmailOptIn, duration: number): boolean => { const timeElapsed = Date.now() - new Date(optIn.updatedAt).getTime() // time is given in minutes return timeElapsed <= duration * 60 * 1000 } - +*/ +const isTimeExpired = (updatedAt: Date, duration: number): boolean => { + const timeElapsed = Date.now() - new Date(updatedAt).getTime() + // time is given in minutes + return timeElapsed <= duration * 60 * 1000 +} +/* const isOptInValid = (optIn: LoginEmailOptIn): boolean => { return isTimeExpired(optIn, CONFIG.EMAIL_CODE_VALID_TIME) } - +*/ +const isEmailVerificationCodeValid = (updatedAt: Date | null): boolean => { + if (updatedAt == null) { + return true + } + return isTimeExpired(updatedAt, CONFIG.EMAIL_CODE_VALID_TIME) +} +/* const canResendOptIn = (optIn: LoginEmailOptIn): boolean => { return !isTimeExpired(optIn, CONFIG.EMAIL_CODE_REQUEST_TIME) } +*/ +const canEmailResend = (updatedAt: Date): boolean => { + return !isTimeExpired(updatedAt, CONFIG.EMAIL_CODE_REQUEST_TIME) +} const getTimeDurationObject = (time: number): { hours?: number; minutes: number } => { if (time > 60) { diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index ad15ebec6..4f1cec0e0 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -15,14 +15,21 @@ export const validateContribution = ( amount: Decimal, creationDate: Date, ): void => { - logger.trace('isContributionValid', creations, amount, creationDate) + logger.trace('isContributionValid: ', creations, amount, creationDate) const index = getCreationIndex(creationDate.getMonth()) if (index < 0) { + logger.error( + 'No information for available creations with the given creationDate=', + creationDate, + ) throw new Error('No information for available creations for the given date') } if (amount.greaterThan(creations[index].toString())) { + logger.error( + `The amount (${amount} GDD) to be created exceeds the amount (${creations[index]} GDD) still available for this month.`, + ) throw new Error( `The amount (${amount} GDD) to be created exceeds the amount (${creations[index]} GDD) still available for this month.`, ) @@ -41,7 +48,7 @@ export const getUserCreations = async ( await queryRunner.connect() const dateFilter = 'last_day(curdate() - interval 3 month) + interval 1 day' - logger.trace('getUserCreations dateFilter', dateFilter) + logger.trace('getUserCreations dateFilter=', dateFilter) const unionString = includePending ? ` @@ -51,6 +58,7 @@ export const getUserCreations = async ( AND contribution_date >= ${dateFilter} AND confirmed_at IS NULL AND deleted_at IS NULL` : '' + logger.trace('getUserCreations unionString=', unionString) const unionQuery = await queryRunner.manager.query(` SELECT MONTH(date) AS month, sum(amount) AS sum, userId AS id FROM @@ -62,6 +70,7 @@ export const getUserCreations = async ( GROUP BY month, userId ORDER BY date DESC `) + logger.trace('getUserCreations unionQuery=', unionQuery) await queryRunner.release() @@ -82,6 +91,7 @@ export const getUserCreations = async ( export const getUserCreation = async (id: number, includePending = true): Promise => { logger.trace('getUserCreation', id, includePending) const creations = await getUserCreations([id], includePending) + logger.trace('getUserCreation creations=', creations) return creations[0] ? creations[0].creations : FULL_CREATION_AVAILABLE } diff --git a/backend/src/mailer/sendAddedContributionMessageEmail.test.ts b/backend/src/mailer/sendAddedContributionMessageEmail.test.ts new file mode 100644 index 000000000..1151a0abc --- /dev/null +++ b/backend/src/mailer/sendAddedContributionMessageEmail.test.ts @@ -0,0 +1,40 @@ +import { sendAddedContributionMessageEmail } from './sendAddedContributionMessageEmail' +import { sendEMail } from './sendEMail' + +jest.mock('./sendEMail', () => { + return { + __esModule: true, + sendEMail: jest.fn(), + } +}) + +describe('sendAddedContributionMessageEmail', () => { + beforeEach(async () => { + await sendAddedContributionMessageEmail({ + senderFirstName: 'Peter', + senderLastName: 'Lustig', + recipientFirstName: 'Bibi', + recipientLastName: 'Bloxberg', + recipientEmail: 'bibi@bloxberg.de', + senderEmail: 'peter@lustig.de', + contributionMemo: 'Vielen herzlichen Dank für den neuen Hexenbesen!', + message: 'Was für ein Besen ist es geworden?', + overviewURL: 'http://localhost/overview', + }) + }) + + it('calls sendEMail', () => { + expect(sendEMail).toBeCalledWith({ + to: `Bibi Bloxberg `, + subject: 'Gradido Frage zur Schöpfung', + text: + expect.stringContaining('Hallo Bibi Bloxberg') && + expect.stringContaining('Peter Lustig') && + expect.stringContaining( + 'Du hast soeben zu deinem eingereichten Gradido Schöpfungsantrag "Vielen herzlichen Dank für den neuen Hexenbesen!" eine Rückfrage von Peter Lustig erhalten.', + ) && + expect.stringContaining('Was für ein Besen ist es geworden?') && + expect.stringContaining('http://localhost/overview'), + }) + }) +}) diff --git a/backend/src/mailer/sendAddedContributionMessageEmail.ts b/backend/src/mailer/sendAddedContributionMessageEmail.ts new file mode 100644 index 000000000..14d5f6d31 --- /dev/null +++ b/backend/src/mailer/sendAddedContributionMessageEmail.ts @@ -0,0 +1,26 @@ +import { backendLogger as logger } from '@/server/logger' +import { sendEMail } from './sendEMail' +import { contributionMessageReceived } from './text/contributionMessageReceived' + +export const sendAddedContributionMessageEmail = (data: { + senderFirstName: string + senderLastName: string + recipientFirstName: string + recipientLastName: string + recipientEmail: string + senderEmail: string + contributionMemo: string + message: string + overviewURL: string +}): Promise => { + logger.info( + `sendEmail(): to=${data.recipientFirstName} ${data.recipientLastName} <${data.recipientEmail}>, + subject=${contributionMessageReceived.de.subject}, + text=${contributionMessageReceived.de.text(data)}`, + ) + return sendEMail({ + to: `${data.recipientFirstName} ${data.recipientLastName} <${data.recipientEmail}>`, + subject: contributionMessageReceived.de.subject, + text: contributionMessageReceived.de.text(data), + }) +} diff --git a/backend/src/mailer/sendContributionConfirmedEmail.test.ts b/backend/src/mailer/sendContributionConfirmedEmail.test.ts new file mode 100644 index 000000000..1935144fd --- /dev/null +++ b/backend/src/mailer/sendContributionConfirmedEmail.test.ts @@ -0,0 +1,39 @@ +import Decimal from 'decimal.js-light' +import { sendContributionConfirmedEmail } from './sendContributionConfirmedEmail' +import { sendEMail } from './sendEMail' + +jest.mock('./sendEMail', () => { + return { + __esModule: true, + sendEMail: jest.fn(), + } +}) + +describe('sendContributionConfirmedEmail', () => { + beforeEach(async () => { + await sendContributionConfirmedEmail({ + senderFirstName: 'Peter', + senderLastName: 'Lustig', + recipientFirstName: 'Bibi', + recipientLastName: 'Bloxberg', + recipientEmail: 'bibi@bloxberg.de', + contributionMemo: 'Vielen herzlichen Dank für den neuen Hexenbesen!', + contributionAmount: new Decimal(200.0), + overviewURL: 'http://localhost/overview', + }) + }) + + it('calls sendEMail', () => { + expect(sendEMail).toBeCalledWith({ + to: 'Bibi Bloxberg ', + subject: 'Schöpfung wurde bestätigt', + text: + expect.stringContaining('Hallo Bibi Bloxberg') && + expect.stringContaining( + 'Dein Gradido Schöpfungsantrag "Vielen herzlichen Dank für den neuen Hexenbesen!" wurde soeben bestätigt.', + ) && + expect.stringContaining('Betrag: 200,00 GDD') && + expect.stringContaining('Link zu deinem Konto: http://localhost/overview'), + }) + }) +}) diff --git a/backend/src/mailer/sendContributionConfirmedEmail.ts b/backend/src/mailer/sendContributionConfirmedEmail.ts new file mode 100644 index 000000000..439d240eb --- /dev/null +++ b/backend/src/mailer/sendContributionConfirmedEmail.ts @@ -0,0 +1,26 @@ +import { backendLogger as logger } from '@/server/logger' +import Decimal from 'decimal.js-light' +import { sendEMail } from './sendEMail' +import { contributionConfirmed } from './text/contributionConfirmed' + +export const sendContributionConfirmedEmail = (data: { + senderFirstName: string + senderLastName: string + recipientFirstName: string + recipientLastName: string + recipientEmail: string + contributionMemo: string + contributionAmount: Decimal + overviewURL: string +}): Promise => { + logger.info( + `sendEmail(): to=${data.recipientFirstName} ${data.recipientLastName} <${data.recipientEmail}>, + subject=${contributionConfirmed.de.subject}, + text=${contributionConfirmed.de.text(data)}`, + ) + return sendEMail({ + to: `${data.recipientFirstName} ${data.recipientLastName} <${data.recipientEmail}>`, + subject: contributionConfirmed.de.subject, + text: contributionConfirmed.de.text(data), + }) +} diff --git a/backend/src/mailer/sendEMail.test.ts b/backend/src/mailer/sendEMail.test.ts index 5746f1ead..a6f4bb62a 100644 --- a/backend/src/mailer/sendEMail.test.ts +++ b/backend/src/mailer/sendEMail.test.ts @@ -73,7 +73,7 @@ describe('sendEMail', () => { it('calls sendMail of transporter', () => { expect((createTransport as jest.Mock).mock.results[0].value.sendMail).toBeCalledWith({ from: `Gradido (nicht antworten) <${CONFIG.EMAIL_SENDER}>`, - to: 'receiver@mail.org', + to: `${CONFIG.EMAIL_TEST_RECEIVER}`, cc: 'support@gradido.net', subject: 'Subject', text: 'Text text text', diff --git a/backend/src/mailer/sendEMail.ts b/backend/src/mailer/sendEMail.ts index 746daa810..00282f232 100644 --- a/backend/src/mailer/sendEMail.ts +++ b/backend/src/mailer/sendEMail.ts @@ -19,6 +19,12 @@ export const sendEMail = async (emailDef: { logger.info(`Emails are disabled via config...`) return false } + if (CONFIG.EMAIL_TEST_MODUS) { + logger.info( + `Testmodus=ON: change receiver from ${emailDef.to} to ${CONFIG.EMAIL_TEST_RECEIVER}`, + ) + emailDef.to = CONFIG.EMAIL_TEST_RECEIVER + } const transporter = createTransport({ host: CONFIG.EMAIL_SMTP_URL, port: Number(CONFIG.EMAIL_SMTP_PORT), diff --git a/backend/src/mailer/sendTransactionLinkRedeemed.test.ts b/backend/src/mailer/sendTransactionLinkRedeemed.test.ts new file mode 100644 index 000000000..b56ff40a1 --- /dev/null +++ b/backend/src/mailer/sendTransactionLinkRedeemed.test.ts @@ -0,0 +1,44 @@ +import { sendEMail } from './sendEMail' +import Decimal from 'decimal.js-light' +import { sendTransactionLinkRedeemedEmail } from './sendTransactionLinkRedeemed' + +jest.mock('./sendEMail', () => { + return { + __esModule: true, + sendEMail: jest.fn(), + } +}) + +describe('sendTransactionLinkRedeemedEmail', () => { + beforeEach(async () => { + await sendTransactionLinkRedeemedEmail({ + email: 'bibi@bloxberg.de', + senderFirstName: 'Peter', + senderLastName: 'Lustig', + recipientFirstName: 'Bibi', + recipientLastName: 'Bloxberg', + senderEmail: 'peter@lustig.de', + amount: new Decimal(42.0), + memo: 'Vielen Dank dass Du dabei bist', + overviewURL: 'http://localhost/overview', + }) + }) + + it('calls sendEMail', () => { + expect(sendEMail).toBeCalledWith({ + to: `Bibi Bloxberg `, + subject: 'Gradido-Link wurde eingelöst', + text: + expect.stringContaining('Hallo Bibi Bloxberg') && + expect.stringContaining( + 'Peter Lustig (peter@lustig.de) hat soeben deinen Link eingelöst.', + ) && + expect.stringContaining('Betrag: 42,00 GDD,') && + expect.stringContaining('Memo: Vielen Dank dass Du dabei bist') && + expect.stringContaining( + 'Details zur Transaktion findest du in deinem Gradido-Konto: http://localhost/overview', + ) && + expect.stringContaining('Bitte antworte nicht auf diese E-Mail!'), + }) + }) +}) diff --git a/backend/src/mailer/sendTransactionLinkRedeemed.ts b/backend/src/mailer/sendTransactionLinkRedeemed.ts new file mode 100644 index 000000000..a78f3b3c9 --- /dev/null +++ b/backend/src/mailer/sendTransactionLinkRedeemed.ts @@ -0,0 +1,28 @@ +import { backendLogger as logger } from '@/server/logger' +import Decimal from 'decimal.js-light' +import { sendEMail } from './sendEMail' +import { transactionLinkRedeemed } from './text/transactionLinkRedeemed' + +export const sendTransactionLinkRedeemedEmail = (data: { + email: string + senderFirstName: string + senderLastName: string + recipientFirstName: string + recipientLastName: string + senderEmail: string + amount: Decimal + memo: string + overviewURL: string +}): Promise => { + logger.info( + `sendEmail(): to=${data.recipientFirstName} ${data.recipientLastName}, + <${data.email}>, + subject=${transactionLinkRedeemed.de.subject}, + text=${transactionLinkRedeemed.de.text(data)}`, + ) + return sendEMail({ + to: `${data.recipientFirstName} ${data.recipientLastName} <${data.email}>`, + subject: transactionLinkRedeemed.de.subject, + text: transactionLinkRedeemed.de.text(data), + }) +} diff --git a/backend/src/mailer/sendTransactionReceivedEmail.test.ts b/backend/src/mailer/sendTransactionReceivedEmail.test.ts index 75631cc7a..9f2ba9938 100644 --- a/backend/src/mailer/sendTransactionReceivedEmail.test.ts +++ b/backend/src/mailer/sendTransactionReceivedEmail.test.ts @@ -19,7 +19,6 @@ describe('sendTransactionReceivedEmail', () => { email: 'peter@lustig.de', senderEmail: 'bibi@bloxberg.de', amount: new Decimal(42.0), - memo: 'Vielen herzlichen Dank für den neuen Hexenbesen!', overviewURL: 'http://localhost/overview', }) }) @@ -33,7 +32,6 @@ describe('sendTransactionReceivedEmail', () => { expect.stringContaining('42,00 GDD') && expect.stringContaining('Bibi Bloxberg') && expect.stringContaining('(bibi@bloxberg.de)') && - expect.stringContaining('Vielen herzlichen Dank für den neuen Hexenbesen!') && expect.stringContaining('http://localhost/overview'), }) }) diff --git a/backend/src/mailer/sendTransactionReceivedEmail.ts b/backend/src/mailer/sendTransactionReceivedEmail.ts index 692f92f9a..5e981659c 100644 --- a/backend/src/mailer/sendTransactionReceivedEmail.ts +++ b/backend/src/mailer/sendTransactionReceivedEmail.ts @@ -11,7 +11,6 @@ export const sendTransactionReceivedEmail = (data: { email: string senderEmail: string amount: Decimal - memo: string overviewURL: string }): Promise => { logger.info( diff --git a/backend/src/mailer/text/contributionConfirmed.ts b/backend/src/mailer/text/contributionConfirmed.ts new file mode 100644 index 000000000..dc82d7615 --- /dev/null +++ b/backend/src/mailer/text/contributionConfirmed.ts @@ -0,0 +1,31 @@ +import Decimal from 'decimal.js-light' + +export const contributionConfirmed = { + de: { + subject: 'Schöpfung wurde bestätigt', + text: (data: { + senderFirstName: string + senderLastName: string + recipientFirstName: string + recipientLastName: string + contributionMemo: string + contributionAmount: Decimal + overviewURL: string + }): string => + `Hallo ${data.recipientFirstName} ${data.recipientLastName}, + +Dein eingereichter Gemeinwohl-Beitrag "${data.contributionMemo}" wurde soeben von ${ + data.senderFirstName + } ${data.senderLastName} bestätigt. + +Betrag: ${data.contributionAmount.toFixed(2).replace('.', ',')} GDD + +Bitte antworte nicht auf diese E-Mail! + +Mit freundlichen Grüßen, +dein Gradido-Team + + +Link zu deinem Konto: ${data.overviewURL}`, + }, +} diff --git a/backend/src/mailer/text/contributionMessageReceived.ts b/backend/src/mailer/text/contributionMessageReceived.ts new file mode 100644 index 000000000..b0c9c4d30 --- /dev/null +++ b/backend/src/mailer/text/contributionMessageReceived.ts @@ -0,0 +1,28 @@ +export const contributionMessageReceived = { + de: { + subject: 'Gradido Frage zur Schöpfung', + text: (data: { + senderFirstName: string + senderLastName: string + recipientFirstName: string + recipientLastName: string + recipientEmail: string + senderEmail: string + contributionMemo: string + message: string + overviewURL: string + }): string => + `Hallo ${data.recipientFirstName} ${data.recipientLastName}, + +du hast soeben zu deinem eingereichten Gemeinwohl-Beitrag "${data.contributionMemo}" eine Rückfrage von ${data.senderFirstName} ${data.senderLastName} erhalten. + +Bitte beantworte die Rückfrage in deinem Gradido-Konto im Menü "Gemeinschaft" im Tab "Meine Beiträge zum Gemeinwohl"! + +Link zu deinem Konto: ${data.overviewURL} + +Bitte antworte nicht auf diese E-Mail! + +Mit freundlichen Grüßen, +dein Gradido-Team`, + }, +} diff --git a/backend/src/mailer/text/transactionLinkRedeemed.ts b/backend/src/mailer/text/transactionLinkRedeemed.ts new file mode 100644 index 000000000..4d8e89cae --- /dev/null +++ b/backend/src/mailer/text/transactionLinkRedeemed.ts @@ -0,0 +1,33 @@ +import Decimal from 'decimal.js-light' + +export const transactionLinkRedeemed = { + de: { + subject: 'Gradido-Link wurde eingelöst', + text: (data: { + email: string + senderFirstName: string + senderLastName: string + recipientFirstName: string + recipientLastName: string + senderEmail: string + amount: Decimal + memo: string + overviewURL: string + }): string => + `Hallo ${data.recipientFirstName} ${data.recipientLastName} + + ${data.senderFirstName} ${data.senderLastName} (${ + data.senderEmail + }) hat soeben deinen Link eingelöst. + + Betrag: ${data.amount.toFixed(2).replace('.', ',')} GDD, + Memo: ${data.memo} + + Details zur Transaktion findest du in deinem Gradido-Konto: ${data.overviewURL} + + Bitte antworte nicht auf diese E-Mail! + + Mit freundlichen Grüßen, + dein Gradido-Team`, + }, +} diff --git a/backend/src/mailer/text/transactionReceived.ts b/backend/src/mailer/text/transactionReceived.ts index 07d03ad45..ba61ae680 100644 --- a/backend/src/mailer/text/transactionReceived.ts +++ b/backend/src/mailer/text/transactionReceived.ts @@ -11,7 +11,6 @@ export const transactionReceived = { email: string senderEmail: string amount: Decimal - memo: string overviewURL: string }): string => `Hallo ${data.recipientFirstName} ${data.recipientLastName} @@ -19,16 +18,12 @@ export const transactionReceived = { Du hast soeben ${data.amount.toFixed(2).replace('.', ',')} GDD von ${data.senderFirstName} ${ data.senderLastName } (${data.senderEmail}) erhalten. -${data.senderFirstName} ${data.senderLastName} schreibt: -${data.memo} +Details zur Transaktion findest du in deinem Gradido-Konto: ${data.overviewURL} Bitte antworte nicht auf diese E-Mail! Mit freundlichen Grüßen, -dein Gradido-Team - - -Link zu deinem Konto: ${data.overviewURL}`, +dein Gradido-Team`, }, } diff --git a/backend/src/seeds/factory/contributionLink.ts b/backend/src/seeds/factory/contributionLink.ts index 5c83b6ad3..d8f31d585 100644 --- a/backend/src/seeds/factory/contributionLink.ts +++ b/backend/src/seeds/factory/contributionLink.ts @@ -11,7 +11,11 @@ export const contributionLinkFactory = async ( const { mutate, query } = client // login as admin - await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } }) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const user = await query({ + query: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) const variables = { amount: contributionLink.amount, diff --git a/backend/src/seeds/factory/creation.ts b/backend/src/seeds/factory/creation.ts index d3f0f78ca..606bac1f7 100644 --- a/backend/src/seeds/factory/creation.ts +++ b/backend/src/seeds/factory/creation.ts @@ -1,13 +1,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { backendLogger as logger } from '@/server/logger' import { adminCreateContribution, confirmContribution } from '@/seeds/graphql/mutations' import { login } from '@/seeds/graphql/queries' import { CreationInterface } from '@/seeds/creation/CreationInterface' import { ApolloServerTestClient } from 'apollo-server-testing' -import { User } from '@entity/User' import { Transaction } from '@entity/Transaction' import { Contribution } from '@entity/Contribution' +import { findUserByEmail } from '@/graphql/resolver/UserResolver' // import CONFIG from '@/config/index' export const nMonthsBefore = (date: Date, months = 1): string => { @@ -19,29 +20,41 @@ export const creationFactory = async ( creation: CreationInterface, ): Promise => { const { mutate, query } = client - + logger.trace('creationFactory...') await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } }) - + logger.trace('creationFactory... after login') // TODO it would be nice to have this mutation return the id await mutate({ mutation: adminCreateContribution, variables: { ...creation } }) + logger.trace('creationFactory... after adminCreateContribution') - const user = await User.findOneOrFail({ where: { email: creation.email } }) + const user = await findUserByEmail(creation.email) // userContact.user const pendingCreation = await Contribution.findOneOrFail({ where: { userId: user.id, amount: creation.amount }, order: { createdAt: 'DESC' }, }) - + logger.trace( + 'creationFactory... after Contribution.findOneOrFail pendingCreation=', + pendingCreation, + ) if (creation.confirmed) { + logger.trace('creationFactory... creation.confirmed=', creation.confirmed) await mutate({ mutation: confirmContribution, variables: { id: pendingCreation.id } }) - + logger.trace('creationFactory... after confirmContribution') const confirmedCreation = await Contribution.findOneOrFail({ id: pendingCreation.id }) + logger.trace( + 'creationFactory... after Contribution.findOneOrFail confirmedCreation=', + confirmedCreation, + ) if (creation.moveCreationDate) { + logger.trace('creationFactory... creation.moveCreationDate=', creation.moveCreationDate) const transaction = await Transaction.findOneOrFail({ where: { userId: user.id, creationDate: new Date(creation.creationDate) }, order: { balanceDate: 'DESC' }, }) + logger.trace('creationFactory... after Transaction.findOneOrFail transaction=', transaction) + if (transaction.decay.equals(0) && transaction.creationDate) { confirmedCreation.contributionDate = new Date( nMonthsBefore(transaction.creationDate, creation.moveCreationDate), @@ -52,11 +65,17 @@ export const creationFactory = async ( transaction.balanceDate = new Date( nMonthsBefore(transaction.balanceDate, creation.moveCreationDate), ) + logger.trace('creationFactory... before transaction.save transaction=', transaction) await transaction.save() + logger.trace( + 'creationFactory... before confirmedCreation.save confirmedCreation=', + confirmedCreation, + ) await confirmedCreation.save() } } } else { + logger.trace('creationFactory... pendingCreation=', pendingCreation) return pendingCreation } } diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index d94f94b3c..d566275db 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -1,6 +1,5 @@ import { createUser, setPassword } from '@/seeds/graphql/mutations' import { User } from '@entity/User' -import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { UserInterface } from '@/seeds/users/UserInterface' import { ApolloServerTestClient } from 'apollo-server-testing' @@ -15,17 +14,23 @@ export const userFactory = async ( createUser: { id }, }, } = await mutate({ mutation: createUser, variables: user }) + // console.log('creatUser:', { id }, { user }) + // get user from database + let dbUser = await User.findOneOrFail({ id }, { relations: ['emailContact'] }) + // console.log('dbUser:', dbUser) + + const emailContact = dbUser.emailContact + // console.log('emailContact:', emailContact) if (user.emailChecked) { - const optin = await LoginEmailOptIn.findOneOrFail({ userId: id }) await mutate({ mutation: setPassword, - variables: { password: 'Aa12345_', code: optin.verificationCode }, + variables: { password: 'Aa12345_', code: emailContact.emailVerificationCode }, }) } - // get user from database - const dbUser = await User.findOneOrFail({ id }) + // get last changes of user from database + dbUser = await User.findOneOrFail({ id }) if (user.createdAt || user.deletedAt || user.isAdmin) { if (user.createdAt) dbUser.createdAt = user.createdAt @@ -34,5 +39,8 @@ export const userFactory = async ( await dbUser.save() } + // get last changes of user from database + // dbUser = await User.findOneOrFail({ id }, { withDeleted: true }) + return dbUser } diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts index 8e9a4e2d8..c5a55cb84 100644 --- a/backend/src/seeds/index.ts +++ b/backend/src/seeds/index.ts @@ -1,6 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { backendLogger as logger } from '@/server/logger' import createServer from '../server/createServer' import { createTestClient } from 'apollo-server-testing' @@ -50,11 +51,14 @@ const run = async () => { const seedClient = createTestClient(server.apollo) const { con } = server await cleanDB() + logger.info('##seed## clean database successful...') // seed the standard users for (let i = 0; i < users.length; i++) { - await userFactory(seedClient, users[i]) + const dbUser = await userFactory(seedClient, users[i]) + logger.info(`##seed## seed standard users[ ${i} ]= ${JSON.stringify(dbUser, null, 2)}`) } + logger.info('##seed## seeding all standard users successful...') // seed 100 random users for (let i = 0; i < 100; i++) { @@ -64,7 +68,9 @@ const run = async () => { email: internet.email(), language: datatype.boolean() ? 'en' : 'de', }) + logger.info(`##seed## seed ${i}. random user`) } + logger.info('##seed## seeding all random users successful...') // create GDD for (let i = 0; i < creations.length; i++) { @@ -73,16 +79,19 @@ const run = async () => { // eslint-disable-next-line no-empty while (new Date().getTime() < now + 1000) {} // we have to wait a little! quick fix for account sum problem of bob@baumeister.de, (see https://github.com/gradido/gradido/issues/1886) } + logger.info('##seed## seeding all creations successful...') // create Transaction Links for (let i = 0; i < transactionLinks.length; i++) { await transactionLinkFactory(seedClient, transactionLinks[i]) } + logger.info('##seed## seeding all transactionLinks successful...') // create Contribution Links for (let i = 0; i < contributionLinks.length; i++) { await contributionLinkFactory(seedClient, contributionLinks[i]) } + logger.info('##seed## seeding all contributionLinks successful...') await con.close() } diff --git a/backend/src/server/context.ts b/backend/src/server/context.ts index d9fd55fe4..5bfc22e72 100644 --- a/backend/src/server/context.ts +++ b/backend/src/server/context.ts @@ -9,6 +9,7 @@ export interface Context { setHeaders: { key: string; value: string }[] role?: Role user?: dbUser + clientRequestTime?: string // hack to use less DB calls for Balance Resolver lastTransaction?: dbTransaction transactionCount?: number @@ -18,14 +19,17 @@ export interface Context { const context = (args: ExpressContext): Context => { const authorization = args.req.headers.authorization - let token: string | null = null - if (authorization) { - token = authorization.replace(/^Bearer /, '') - } - const context = { - token, + const clientRequestTime = args.req.headers.clientrequesttime + const context: Context = { + token: null, setHeaders: [], } + if (authorization) { + context.token = authorization.replace(/^Bearer /, '') + } + if (clientRequestTime && typeof clientRequestTime === 'string') { + context.clientRequestTime = clientRequestTime + } return context } diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index a0b294281..d1153cdb6 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -75,6 +75,9 @@ const createServer = async ( logger, }) apollo.applyMiddleware({ app, path: '/' }) + logger.info( + `running with PRODUCTION=${CONFIG.PRODUCTION}, sending EMAIL enabled=${CONFIG.EMAIL} and EMAIL_TEST_MODUS=${CONFIG.EMAIL_TEST_MODUS} ...`, + ) logger.debug('createServer...successful') return { apollo, app, con } } diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts index 01f61dcbc..8b3e29859 100644 --- a/backend/src/typeorm/repository/User.ts +++ b/backend/src/typeorm/repository/User.ts @@ -1,28 +1,39 @@ -import { Brackets, EntityRepository, ObjectLiteral, Repository } from '@dbTools/typeorm' -import { User } from '@entity/User' +import SearchUsersFilters from '@/graphql/arg/SearchUsersFilters' +import { Brackets, EntityRepository, IsNull, Not, Repository } from '@dbTools/typeorm' +import { User as DbUser } from '@entity/User' -@EntityRepository(User) -export class UserRepository extends Repository { - async findByPubkeyHex(pubkeyHex: string): Promise { - return this.createQueryBuilder('user') +@EntityRepository(DbUser) +export class UserRepository extends Repository { + async findByPubkeyHex(pubkeyHex: string): Promise { + const dbUser = await this.createQueryBuilder('user') + .leftJoinAndSelect('user.emailContact', 'emailContact') .where('hex(user.pubKey) = :pubkeyHex', { pubkeyHex }) .getOneOrFail() + /* + const dbUser = await this.findOneOrFail(`hex(user.pubKey) = { pubkeyHex }`) + const emailContact = await this.query( + `SELECT * from user_contacts where id = { dbUser.emailId }`, + ) + dbUser.emailContact = emailContact + */ + return dbUser } async findBySearchCriteriaPagedFiltered( select: string[], searchCriteria: string, - filterCriteria: ObjectLiteral[], + filters: SearchUsersFilters, currentPage: number, pageSize: number, - ): Promise<[User[], number]> { - const query = await this.createQueryBuilder('user') + ): Promise<[DbUser[], number]> { + const query = this.createQueryBuilder('user') .select(select) + .leftJoinAndSelect('user.emailContact', 'emailContact') .withDeleted() .where( new Brackets((qb) => { qb.where( - 'user.firstName like :name or user.lastName like :lastName or user.email like :email', + 'user.firstName like :name or user.lastName like :lastName or emailContact.email like :email', { name: `%${searchCriteria}%`, lastName: `%${searchCriteria}%`, @@ -31,9 +42,23 @@ export class UserRepository extends Repository { ) }), ) + /* filterCriteria.forEach((filter) => { query.andWhere(filter) }) + */ + if (filters) { + if (filters.byActivated !== null) { + query.andWhere('emailContact.emailChecked = :value', { value: filters.byActivated }) + // filterCriteria.push({ 'emailContact.emailChecked': filters.byActivated }) + } + + if (filters.byDeleted !== null) { + // filterCriteria.push({ deletedAt: filters.byDeleted ? Not(IsNull()) : IsNull() }) + query.andWhere({ deletedAt: filters.byDeleted ? Not(IsNull()) : IsNull() }) + } + } + return query .take(pageSize) .skip((currentPage - 1) * pageSize) diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index d850c5382..e885b7043 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -2,22 +2,26 @@ import { SaveOptions, RemoveOptions } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' +import { UserContact } from '@entity/UserContact' +// import { UserContact as EmailContact } from '@entity/UserContact' import { User } from '@model/User' const communityDbUser: dbUser = { id: -1, gradidoID: '11111111-2222-4333-4444-55555555', alias: '', - email: 'support@gradido.net', + // email: 'support@gradido.net', + emailContact: new UserContact(), + emailId: -1, firstName: 'Gradido', lastName: 'Akademie', pubKey: Buffer.from(''), privKey: Buffer.from(''), deletedAt: null, password: BigInt(0), - emailHash: Buffer.from(''), + // emailHash: Buffer.from(''), createdAt: new Date(), - emailChecked: false, + // emailChecked: false, language: '', isAdmin: null, publisherId: 0, diff --git a/backend/src/util/klicktipp.ts b/backend/src/util/klicktipp.ts index c8f83acc3..0432f196e 100644 --- a/backend/src/util/klicktipp.ts +++ b/backend/src/util/klicktipp.ts @@ -7,16 +7,16 @@ export async function retrieveNotRegisteredEmails(): Promise { if (!con) { throw new Error('No connection to database') } - const users = await User.find() + const users = await User.find({ relations: ['emailContact'] }) const notRegisteredUser = [] for (let i = 0; i < users.length; i++) { const user = users[i] try { - await getKlickTippUser(user.email) + await getKlickTippUser(user.emailContact.email) } catch (err) { - notRegisteredUser.push(user.email) + notRegisteredUser.push(user.emailContact.email) // eslint-disable-next-line no-console - console.log(`${user.email}`) + console.log(`${user.emailContact.email}`) } } await con.close() diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index d5eaef521..87af4088c 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -29,7 +29,7 @@ import { LoginElopageBuys } from '@entity/LoginElopageBuys' import { UserResolver } from '@/graphql/resolver/UserResolver' -import { User as dbUser } from '@entity/User' +import { UserContact as dbUserContact } from '@entity/UserContact' export const elopageWebhook = async (req: any, res: any): Promise => { // eslint-disable-next-line no-console @@ -127,7 +127,8 @@ export const elopageWebhook = async (req: any, res: any): Promise => { } // Do we already have such a user? - if ((await dbUser.count({ email })) !== 0) { + // if ((await dbUser.count({ email })) !== 0) { + if ((await dbUserContact.count({ email })) !== 0) { // eslint-disable-next-line no-console console.log(`Did not create User - already exists with email: ${email}`) return diff --git a/database/entity/0049-add_user_contacts_table/User.ts b/database/entity/0049-add_user_contacts_table/User.ts new file mode 100644 index 000000000..abe40df54 --- /dev/null +++ b/database/entity/0049-add_user_contacts_table/User.ts @@ -0,0 +1,126 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, + OneToOne, +} from 'typeorm' +import { Contribution } from '../Contribution' +import { ContributionMessage } from '../ContributionMessage' +import { UserContact } from '../UserContact' + +@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: false, + collation: 'utf8mb4_unicode_ci', + }) + gradidoID: string + + @Column({ + name: 'alias', + length: 20, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + alias: string + + @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true }) + pubKey: Buffer + + @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) + privKey: Buffer + + /* + @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) + email: 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 + + @DeleteDateColumn() + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + /* + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) + emailChecked: boolean + */ + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ name: 'is_admin', type: 'datetime', nullable: true, default: null }) + isAdmin: Date | null + + @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({ + type: 'text', + name: 'passphrase', + collation: 'utf8mb4_unicode_ci', + nullable: true, + default: null, + }) + passphrase: string + + @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[] +} diff --git a/database/entity/0049-add_user_contacts_table/UserContact.ts b/database/entity/0049-add_user_contacts_table/UserContact.ts new file mode 100644 index 000000000..97b12d4cd --- /dev/null +++ b/database/entity/0049-add_user_contacts_table/UserContact.ts @@ -0,0 +1,60 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToOne, +} from 'typeorm' +import { User } from './User' + +@Entity('user_contacts', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class UserContact extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ + name: 'type', + length: 100, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + type: string + + @OneToOne(() => User, (user) => user.emailContact) + user: User + + @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: false }) + userId: number + + @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) + email: string + + @Column({ name: 'email_verification_code', type: 'bigint', unsigned: true, unique: true }) + emailVerificationCode: BigInt + + @Column({ name: 'email_opt_in_type_id' }) + emailOptInTypeId: number + + @Column({ name: 'email_resend_count' }) + emailResendCount: number + + // @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + // emailHash: Buffer + + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) + emailChecked: boolean + + @Column({ length: 255, unique: false, nullable: true, collation: 'utf8mb4_unicode_ci' }) + phone: string + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + + @Column({ name: 'updated_at', nullable: true, default: null, type: 'datetime' }) + updatedAt: Date | null + + @DeleteDateColumn({ name: 'deleted_at', nullable: true }) + deletedAt: Date | null +} diff --git a/database/entity/User.ts b/database/entity/User.ts index 7d15bf559..d073f428a 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0047-messages_tables/User' +export { User } from './0049-add_user_contacts_table/User' diff --git a/database/entity/UserContact.ts b/database/entity/UserContact.ts new file mode 100644 index 000000000..a368bb7ca --- /dev/null +++ b/database/entity/UserContact.ts @@ -0,0 +1 @@ +export { UserContact } from './0049-add_user_contacts_table/UserContact' diff --git a/database/entity/index.ts b/database/entity/index.ts index abd31bfb9..a82ef561c 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -5,6 +5,7 @@ import { Migration } from './Migration' import { Transaction } from './Transaction' import { TransactionLink } from './TransactionLink' import { User } from './User' +import { UserContact } from './UserContact' import { Contribution } from './Contribution' import { EventProtocol } from './EventProtocol' import { ContributionMessage } from './ContributionMessage' @@ -20,4 +21,5 @@ export const entities = [ User, EventProtocol, ContributionMessage, + UserContact, ] diff --git a/database/migrations/0049-add_user_contacts_table.ts b/database/migrations/0049-add_user_contacts_table.ts new file mode 100644 index 000000000..c3b89ed88 --- /dev/null +++ b/database/migrations/0049-add_user_contacts_table.ts @@ -0,0 +1,129 @@ +/* MIGRATION TO ADD GRADIDO_ID + * + * This migration adds new columns to the table `users` and creates the + * new table `user_contacts` + */ + +/* 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 IF NOT EXISTS \`user_contacts\` ( + \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, + \`type\` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, + \`user_id\` int(10) unsigned NOT NULL, + \`email\` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL UNIQUE, + \`email_verification_code\` bigint(20) unsigned NOT NULL UNIQUE, + \`email_opt_in_type_id\` int NOT NULL, + \`email_resend_count\` int DEFAULT '0', + \`email_checked\` tinyint(4) NOT NULL DEFAULT 0, + \`phone\` varchar(255) COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, + \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + \`updated_at\` datetime(3) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(3), + \`deleted_at\` datetime(3) NULL DEFAULT NULL, + PRIMARY KEY (\`id\`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) + + await queryFn('ALTER TABLE `users` ADD COLUMN `email_id` int(10) NULL AFTER `email`;') + // define datetime column with a precision of 3 milliseconds + await queryFn( + 'ALTER TABLE `users` MODIFY COLUMN `created` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) AFTER `email_hash`;', + ) + // define datetime column with a precision of 3 milliseconds + await queryFn( + 'ALTER TABLE `users` MODIFY COLUMN `deletedAt` datetime(3) NULL DEFAULT NULL AFTER `last_name`;', + ) + // define datetime column with a precision of 3 milliseconds + await queryFn( + 'ALTER TABLE `users` MODIFY COLUMN `is_admin` datetime(3) NULL DEFAULT NULL AFTER `language`;', + ) + + // merge values from login_email_opt_in table with users.email in new user_contacts table + await queryFn(` + INSERT INTO user_contacts + (type, user_id, email, email_verification_code, email_opt_in_type_id, email_resend_count, email_checked, created_at, updated_at, deleted_at) + SELECT + 'EMAIL', + u.id as user_id, + u.email, + e.verification_code as email_verification_code, + e.email_opt_in_type_id, + e.resend_count as email_resend_count, + u.email_checked, + e.created as created_at, + e.updated as updated_at, + u.deletedAt as deleted_at\ + FROM + users as u, + login_email_opt_in as e + WHERE + u.id = e.user_id AND + e.id in ( + WITH opt_in AS ( + SELECT + le.id, le.user_id, le.created, le.updated, ROW_NUMBER() OVER (PARTITION BY le.user_id ORDER BY le.created DESC) AS row_num + FROM + login_email_opt_in as le + ) + SELECT + opt_in.id + FROM + opt_in + WHERE + row_num = 1);`) + /* + // SELECT + // le.id + // FROM + // login_email_opt_in as le + // WHERE + // le.user_id = u.id + // ORDER BY + // le.updated DESC, le.created DESC LIMIT 1);`) + */ + + // insert in users table the email_id of the new created email-contacts + const contacts = await queryFn(`SELECT c.id, c.user_id FROM user_contacts as c`) + for (const id in contacts) { + const contact = contacts[id] + await queryFn( + `UPDATE users as u SET u.email_id = "${contact.id}" WHERE u.id = "${contact.user_id}"`, + ) + } + // these steps comes after verification and test + await queryFn('ALTER TABLE users DROP COLUMN email;') + await queryFn('ALTER TABLE users DROP COLUMN email_checked;') +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + // this step comes after verification and test + await queryFn('ALTER TABLE users ADD COLUMN email varchar(255) NULL AFTER privkey;') + await queryFn( + 'ALTER TABLE users ADD COLUMN email_checked tinyint(4) NOT NULL DEFAULT 0 AFTER email;', + ) + await queryFn( + 'ALTER TABLE `users` MODIFY COLUMN `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `email_hash`;', + ) + await queryFn( + 'ALTER TABLE `users` MODIFY COLUMN `deletedAt` datetime NULL DEFAULT NULL AFTER `last_name`;', + ) + await queryFn( + 'ALTER TABLE `users` MODIFY COLUMN `is_admin` datetime NULL DEFAULT NULL AFTER `language`;', + ) + + // reconstruct the previous email back from contacts to users table + const contacts = await queryFn(`SELECT c.id, c.email, c.user_id FROM user_contacts as c`) + for (const id in contacts) { + const contact = contacts[id] + await queryFn( + `UPDATE users SET email = "${contact.email}" WHERE id = "${contact.user_id}" and email_id = "${contact.id}"`, + ) + } + await queryFn('ALTER TABLE users MODIFY COLUMN email varchar(255) NOT NULL UNIQUE;') + + // write downgrade logic as parameter of queryFn + await queryFn(`DROP TABLE IF EXISTS user_contacts;`) + + await queryFn('ALTER TABLE users DROP COLUMN email_id;') +} diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 1255104c9..b090908e1 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -26,10 +26,11 @@ COMMUNITY_REDEEM_CONTRIBUTION_URL=https://stage1.gradido.net/redeem/CL-{code} COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community" # backend -BACKEND_CONFIG_VERSION=v9.2022-07-07 +BACKEND_CONFIG_VERSION=v10.2022-09-20 JWT_EXPIRES_IN=10m GDT_API_URL=https://gdt.gradido.net +ENV_NAME=stage1 TYPEORM_LOGGING_RELATIVE_PATH=../deployment/bare_metal/log/typeorm.backend.log @@ -40,6 +41,8 @@ KLICKTIPP_APIKEY_DE= KLICKTIPP_APIKEY_EN= EMAIL=true +EMAIL_TEST_MODUS=false +EMAIL_TEST_RECEIVER=test_team@gradido.net EMAIL_USERNAME=peter@lustig.de EMAIL_SENDER=peter@lustig.de EMAIL_PASSWORD=1234 @@ -61,7 +64,7 @@ EVENT_PROTOCOL_DISABLED=false DATABASE_CONFIG_VERSION=v1.2022-03-18 # frontend -FRONTEND_CONFIG_VERSION=v2.2022-04-07 +FRONTEND_CONFIG_VERSION=v3.2022-09-16 GRAPHQL_URI=https://stage1.gradido.net/graphql ADMIN_AUTH_URL=https://stage1.gradido.net/admin/authenticate?token={token} @@ -77,6 +80,8 @@ META_KEYWORDS_DE="Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natü META_KEYWORDS_EN="Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System" META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" +SUPPORT_MAIL=support@supportmail.com + # admin ADMIN_CONFIG_VERSION=v1.2022-03-18 diff --git a/deployment/bare_metal/install.sh b/deployment/bare_metal/install.sh index 01b1e7a0b..9e60bec08 100755 --- a/deployment/bare_metal/install.sh +++ b/deployment/bare_metal/install.sh @@ -81,7 +81,7 @@ pm2 startup sudo apt-get install -y certbot sudo apt-get install -y python3-certbot-nginx sudo certbot -> Enter email address (used for urgent renewal and security notices) > support@gradido.net +> Enter email address (used for urgent renewal and security notices) > e.g. support@supportmail.com > Please read the Terms of Service at > Y > Would you be willing, once your first certificate is successfully issued, to > N > No names were found in your configuration files. Please enter in your domain > stage1.gradido.net @@ -137,6 +137,10 @@ envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env # Configure admin envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env +# create cronjob to delete yarn output in /tmp +# crontab -e +# hourly job: 0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null +# daily job: 0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null # Start gradido # Note: on first startup some errors will occur - nothing serious ./start.sh diff --git a/deployment/bare_metal/setup.md b/deployment/bare_metal/setup.md index 1bce53b26..8f09d296b 100644 --- a/deployment/bare_metal/setup.md +++ b/deployment/bare_metal/setup.md @@ -192,3 +192,14 @@ Use it as pattern to do all steps manually in your terminal shell. - *The commands for setting the paths in the used env variables are not working directly in the terminal, consider the out commented commands for this purpose.* Follow the commands in `./install.sh` as installation pattern. + +## Define cronjob to compensate yarn output in /tmp + +> yarn creates output in /tmp directory, which must be deleted regularly and will be done per cronjob +> on stage1 a hourly job is necessary by setting the following job in the crontab for the gradido user +> crontab -e opens the crontab in edit-mode and insert the following entry: +> "0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null" +> on stage2 a daily job is necessary by setting the following job in the crontab for the gradido user +> crontab -e opens the crontab in edit-mode and insert the following entry: +> "0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null" + diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 2af3c41ee..fe2f68a8d 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,122 +1,122 @@ -version: "3.4" - -services: - - ######################################################## - # FRONTEND ############################################# - ######################################################## - frontend: - # 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/frontend:local-development - build: - target: development - environment: - - NODE_ENV="development" - # - DEBUG=true - 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 - - frontend_node_modules:/app/node_modules - # bind the local folder to the docker to allow live reload - - ./frontend:/app - - ######################################################## - # ADMIN INTERFACE ###################################### - ######################################################## - admin: - # 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/admin:local-development - build: - target: development - environment: - - NODE_ENV="development" - # - DEBUG=true - 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 - - admin_node_modules:/app/node_modules - # bind the local folder to the docker to allow live reload - - ./admin:/app - - ######################################################## - # BACKEND ############################################## - ######################################################## - backend: - # 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/backend: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 - - backend_node_modules:/app/node_modules - - backend_database_node_modules:/database/node_modules - - backend_database_build:/database/build - # bind the local folder to the docker to allow live reload - - ./backend:/app - - ./database:/database - - ######################################################## - # DATABASE ############################################## - ######################################################## - 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/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 - - database_node_modules:/app/node_modules - - database_build:/app/build - # bind the local folder to the docker to allow live reload - - ./database:/app - - ######################################################### - ## MARIADB ############################################## - ######################################################### - mariadb: - networks: - - internal-net - - external-net - - ######################################################### - ## NGINX ################################################ - ######################################################### - # nginx: - - ######################################################### - ## PHPMYADMIN ########################################### - ######################################################### - phpmyadmin: - image: phpmyadmin - environment: - - PMA_ARBITRARY=1 - #restart: always - ports: - - 8074:80 - networks: - - internal-net - - external-net - volumes: - - /sessions - -volumes: - frontend_node_modules: - admin_node_modules: - backend_node_modules: - backend_database_node_modules: - backend_database_build: - database_node_modules: - database_build: +version: "3.4" + +services: + + ######################################################## + # FRONTEND ############################################# + ######################################################## + frontend: + # 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/frontend:local-development + build: + target: development + environment: + - NODE_ENV="development" + # - DEBUG=true + 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 + - frontend_node_modules:/app/node_modules + # bind the local folder to the docker to allow live reload + - ./frontend:/app + + ######################################################## + # ADMIN INTERFACE ###################################### + ######################################################## + admin: + # 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/admin:local-development + build: + target: development + environment: + - NODE_ENV="development" + # - DEBUG=true + 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 + - admin_node_modules:/app/node_modules + # bind the local folder to the docker to allow live reload + - ./admin:/app + + ######################################################## + # BACKEND ############################################## + ######################################################## + backend: + # 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/backend: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 + - backend_node_modules:/app/node_modules + - backend_database_node_modules:/database/node_modules + - backend_database_build:/database/build + # bind the local folder to the docker to allow live reload + - ./backend:/app + - ./database:/database + + ######################################################## + # DATABASE ############################################## + ######################################################## + 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/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 + - database_node_modules:/app/node_modules + - database_build:/app/build + # bind the local folder to the docker to allow live reload + - ./database:/app + + ######################################################### + ## MARIADB ############################################## + ######################################################### + mariadb: + networks: + - internal-net + - external-net + + ######################################################### + ## NGINX ################################################ + ######################################################### + # nginx: + + ######################################################### + ## PHPMYADMIN ########################################### + ######################################################### + phpmyadmin: + image: phpmyadmin + environment: + - PMA_ARBITRARY=1 + #restart: always + ports: + - 8074:80 + networks: + - internal-net + - external-net + volumes: + - /sessions + +volumes: + frontend_node_modules: + admin_node_modules: + backend_node_modules: + backend_database_node_modules: + backend_database_build: + database_node_modules: + database_build: diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 7db318176..79ee46906 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,61 +1,62 @@ -version: "3.4" - -services: - - ######################################################## - # BACKEND ############################################## - ######################################################## - backend: - # 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/backend:test - build: - target: test - networks: - - external-net - - internal-net - environment: - - NODE_ENV="test" - - DB_HOST=mariadb - - ######################################################## - # DATABASE ############################################# - ######################################################## - database: - build: - context: ./database - target: test_up - # restart: always # this is very dangerous, but worth a test for the delayed mariadb startup at first run - - ######################################################### - ## MARIADB ############################################## - ######################################################### - mariadb: - networks: - - internal-net - - external-net - volumes: - - db_test_vol:/var/lib/mysql - - ######################################################### - ## PHPMYADMIN ########################################### - ######################################################### - phpmyadmin: - image: phpmyadmin - environment: - - PMA_ARBITRARY=1 - #restart: always - ports: - - 8074:80 - networks: - - internal-net - - external-net - volumes: - - /sessions - -networks: - external-net: - internal-net: - internal: true - -volumes: - db_test_vol: +version: "3.4" + +services: + + ######################################################## + # BACKEND ############################################## + ######################################################## + backend: + # 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/backend:test + build: + target: test + networks: + - external-net + - internal-net + environment: + - NODE_ENV="test" + - DB_HOST=mariadb + + ######################################################## + # DATABASE ############################################# + ######################################################## + database: + build: + context: ./database + target: test_up + # restart: always # this is very dangerous, but worth a test for the delayed mariadb startup at first run + + ######################################################### + ## MARIADB ############################################## + ######################################################### + mariadb: + networks: + - internal-net + - external-net + volumes: + - db_test_vol:/var/lib/mysql + + ######################################################### + ## PHPMYADMIN ########################################### + ######################################################### + phpmyadmin: + image: phpmyadmin + environment: + - PMA_ARBITRARY=1 + #restart: always + ports: + - 8074:80 + networks: + - internal-net + - external-net + volumes: + - /sessions + +networks: + external-net: + internal-net: + internal: true + +volumes: + db_test_vol: + diff --git a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md index f8cf2cd03..ecdf8df34 100644 --- a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md +++ b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md @@ -6,30 +6,41 @@ With the business event protocol the gradido application will capture and persis The different event types will be defined as Enum. The following list is a first draft and will grow with further event types in the future. -| EventType | Value | Description | -| ----------------------------------- | ----- | ------------------------------------------------------------------------------------------------------ | -| BasicEvent | 0 | the basic event is the root of all further extending event types | -| VisitGradidoEvent | 10 | if a user visits a gradido page without login or register | -| RegisterEvent | 20 | the user presses the register button | -| RedeemRegisterEvent | 21 | the user presses the register button initiated by the redeem link | -| InActiveAccountEvent | 22 | the systems create an inactive account during the register process | -| SendConfirmEmailEvent | 23 | the system send a confirmation email to the user during the register process | -| ConfirmEmailEvent | 24 | the user confirms his email during the register process | -| RegisterEmailKlickTippEvent | 25 | the system registers the confirmed email at klicktipp | -| LoginEvent | 30 | the user presses the login button | -| RedeemLoginEvent | 31 | the user presses the login button initiated by the redeem link | -| ActivateAccountEvent | 32 | the system activates the users account during the first login process | -| PasswordChangeEvent | 33 | the user changes his password | -| TransactionSendEvent | 40 | the user creates a transaction and sends it online | -| TransactionSendRedeemEvent | 41 | the user creates a transaction and sends it per redeem link | -| TransactionRepeateRedeemEvent | 42 | the user recreates a redeem link of a still open transaction | -| TransactionCreationEvent | 50 | the user receives a creation transaction for his confirmed contribution | -| TransactionReceiveEvent | 51 | the user receives a transaction from an other user and posts the amount on his account | -| TransactionReceiveRedeemEvent | 52 | the user activates the redeem link and receives the transaction and posts the amount on his account | -| ContributionCreateEvent | 60 | the user enters his contribution and asks for confirmation | -| ContributionConfirmEvent | 61 | the user confirms a contribution of an other user (for future multi confirmation from several users) | -| ContributionLinkDefineEvent | 70 | the admin user defines a contributionLink, which could be send per Link/QR-Code on an other medium | -| ContributionLinkActivateRedeemEvent | 71 | the user activates a received contributionLink to create a contribution entry for the contributionLink | +| EventType | Description | +| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| BasicEvent | the basic event is the root of all further extending event types | +| VisitGradidoEvent | if a user visits a gradido page without login or register; possible as soon as a request-response-loop for the first page will be invoked | +| RegisterEvent | the user presses the register button | +| LoginEvent | the user presses the login button | +| VerifyRedeemEvent | the user presses a redeem link independent from transaction or contribution redeem | +| RedeemRegisterEvent | the user presses the register-button initiated by the redeem link | +| RedeemLoginEvent | the user presses the login-button initiated by the redeem link | +| ActivateAccountEvent | the system activates the users account after a successful confirmEmail-Event or during a reactivation of a deactivated account | +| InActiveAccountEvent | the systems creates an inactive account during the register process or an active account will be reset to inactive | +| SetPasswordEvent | the system sets a new password after ConfirmEmailEvent or SendForgotPasswordEvent | +| RegisterEmailKlickTippEvent | the system registers the confirmed email at klicktipp | +| PasswordChangeEvent | the user changes his password in his Profile | +| TransactionSendEvent | the user creates a transaction and sends it online; paired with TransactionReceiveEvent | +| TransactionLinkCreateEvent | the user creates a transaction link | +| TransactionReceiveEvent | the user receives a transaction from an other user and posts the amount on his account; paired with TransactionSendEvent | +| TransactionLinkRedeemEvent | the user activates the redeem link and receives the transaction and posts the amount on his account | +| ContributionCreateEvent | the user enters his contribution and asks for confirmation | +| ContributionConfirmEvent | the admin user confirms a contribution of an other user (for future multi confirmation from several users) | +| ContributionDenyEvent | the admin user denies a contribution of an other user | +| ContributionLinkDefineEvent | the admin user defines a contributionLink, which could be send per Link/QR-Code on an other medium | +| ContributionLinkRedeemEvent | the user activates a received contributionLink to create a contribution entry for the contributionLink | +| UserCreateContributionMessageEvent | the user captures a new message for a contribution | +| AdminCreateContributionMessageEvent | the admin user captures a new message for a contribution | +| LogoutEvent | the user invokes a logout | +| SendConfirmEmailEvent | the system sends a confirmation email to the user during the registration process | +| SendAccountMultiRegistrationEmailEvent | the system sends a info email to the user, that an other user tries to register with his existing email address | +| SendForgotPasswordEmailEvent | the system sends the forgot password email including a special link to start the forgot password process | +| SendTransactionSendEmailEvent | the system sends an email to inform the user about his transaction was sent to an other user | +| SendTransactionReceiveEmailEvent | the system sends an email to inform the user about a received transaction from an other user | +| SendAddedContributionEmailEvent | the system sends an email to inform the user about the creation of his captured contribution | +| SendContributionConfirmEmailEvent | the system sends an email to inform the user about the confirmation of his contribution | +| SendTransactionLinkRedeemEmailEvent | the system sends an email to the user, who created the transactionlink, that the link was redeemed | +| | | ## EventProtocol - Entity @@ -49,32 +60,44 @@ The business events will be stored in database in the new table `EventProtocol`. ## Event Types -The following table lists for each event type the mandatory attributes, which have to be initialized at event occurence and to be written in the database event protocol table: +The following table lists for each event type the mapping between old and new key, the mandatory attributes, which have to be initialized at event occurence and to be written in the database event protocol table: -| EventType | id | type | createdAt | userID | XuserID | XCommunityID | transactionID | contribID | amount | -| :---------------------------------- | :-: | :--: | :-------: | :----: | :-----: | :----------: | :-----------: | :-------: | :----: | -| BasicEvent | x | x | x | | | | | | | -| VisitGradidoEvent | x | x | x | | | | | | | -| RegisterEvent | x | x | x | x | | | | | | -| RedeemRegisterEvent | x | x | x | x | | | (x) | (x) | | -| InActiveAccountEvent | x | x | x | x | | | | | | -| SendConfirmEmailEvent | x | x | x | x | | | | | | -| ConfirmEmailEvent | x | x | x | x | | | | | | -| RegisterEmailKlickTippEvent | x | x | x | x | | | | | | -| LoginEvent | x | x | x | x | | | | | | -| RedeemLoginEvent | x | x | x | x | | | (x) | (x) | | -| ActivateAccountEvent | x | x | x | x | | | | | | -| PasswordChangeEvent | x | x | x | x | | | | | | -| TransactionSendEvent | x | x | x | x | x | x | x | | x | -| TransactionSendRedeemEvent | x | x | x | x | x | x | x | | x | -| TransactionRepeateRedeemEvent | x | x | x | x | x | x | x | | x | -| TransactionCreationEvent | x | x | x | x | | | x | | x | -| TransactionReceiveEvent | x | x | x | x | x | x | x | | x | -| TransactionReceiveRedeemEvent | x | x | x | x | x | x | x | | x | -| ContributionCreateEvent | x | x | x | x | | | | x | x | -| ContributionConfirmEvent | x | x | x | x | x | x | | x | x | -| ContributionLinkDefineEvent | x | x | x | x | | | | | x | -| ContributionLinkActivateRedeemEvent | x | x | x | x | | | | x | x | +| EventType - old key | EventType - new key | id | type | createdAt | userID | XuserID | XCommunityID | transactionID | contribID | amount | +| :-------------------------------- | :------------------------------------- | :-: | :--: | :-------: | :----: | :-----: | :----------: | :-----------: | :-------: | :----: | +| BASIC | BasicEvent | x | x | x | | | | | | | +| VISIT_GRADIDO | VisitGradidoEvent | x | x | x | | | | | | | +| REGISTER | RegisterEvent | x | x | x | x | | | | | | +| LOGIN | LoginEvent | x | x | x | x | | | | | | +| | VerifyRedeemEvent | | | | | | | | | | +| REDEEM_REGISTER | RedeemRegisterEvent | x | x | x | x | | | (x) | (x) | | +| REDEEM_LOGIN | RedeemLoginEvent | x | x | x | x | | | (x) | (x) | | +| ACTIVATE_ACCOUNT | ActivateAccountEvent | x | x | x | x | | | | | | +| INACTIVE_ACCOUNT | InActiveAccountEvent | x | x | x | x | | | | | | +| CONFIRM_EMAIL | SetPasswordEvent | x | x | x | x | | | | | | +| REGISTER_EMAIL_KLICKTIPP | RegisterEmailKlickTippEvent | x | x | x | x | | | | | | +| PASSWORD_CHANGE | PasswordChangeEvent | x | x | x | x | | | | | | +| TRANSACTION_SEND | TransactionSendEvent | x | x | x | x | x | x | x | | x | +| TRANSACTION_CREATION | TransactionLinkCreateEvent | x | x | x | x | | | x | | x | +| TRANSACTION_RECEIVE | TransactionReceiveEvent | x | x | x | x | x | x | x | | x | +| TRANSACTION_SEND_REDEEM | TransactionLinkRedeemEvent | x | x | x | x | x | x | x | | x | +| CONTRIBUTION_CREATE | ContributionCreateEvent | x | x | x | x | | | | x | x | +| CONTRIBUTION_CONFIRM | ContributionConfirmEvent | x | x | x | x | x | x | | x | x | +| | ContributionDenyEvent | x | x | x | x | x | x | | x | x | +| CONTRIBUTION_LINK_DEFINE | ContributionLinkDefineEvent | x | x | x | x | | | | | x | +| CONTRIBUTION_LINK_ACTIVATE_REDEEM | ContributionLinkRedeemEvent | x | x | x | x | | | | x | x | +| | UserCreateContributionMessageEvent | x | x | x | x | | | | x | x | +| | AdminCreateContributionMessageEvent | x | x | x | x | | | | x | x | +| | LogoutEvent | x | x | x | x | | | | x | x | +| SEND_CONFIRMATION_EMAIL | SendConfirmEmailEvent | x | x | x | x | | | | | | +| | SendAccountMultiRegistrationEmailEvent | x | x | x | x | | | | | | +| | SendForgotPasswordEmailEvent | x | x | x | x | | | | | | +| | SendTransactionSendEmailEvent | x | x | x | x | x | x | x | | x | +| | SendTransactionReceiveEmailEvent | x | x | x | x | x | x | x | | x | +| | SendAddedContributionEmailEvent | x | x | x | x | | | | x | x | +| | SendContributionConfirmEmailEvent | x | x | x | x | | | | x | x | +| | SendTransactionLinkRedeemEmailEvent | x | x | x | x | x | x | x | | x | +| TRANSACTION_REPEATE_REDEEM | - | | | | | | | | | | +| TRANSACTION_RECEIVE_REDEEM | - | | | | | | | | | | ## Event creation diff --git a/docu/Concepts/TechnicalRequirements/UC_Introduction_of_Gradido-ID.md b/docu/Concepts/TechnicalRequirements/UC_Introduction_of_Gradido-ID.md index e3c0ac2d7..9d607ba97 100644 --- a/docu/Concepts/TechnicalRequirements/UC_Introduction_of_Gradido-ID.md +++ b/docu/Concepts/TechnicalRequirements/UC_Introduction_of_Gradido-ID.md @@ -2,7 +2,7 @@ ## Motivation -To introduce the Gradido-ID base on the requirement to identify an user account per technical key instead of using an email-address. Such a technical key ensures an exact identification of an user account without giving detailed information for possible missusage. +The introduction of the Gradido-ID base on the requirement to identify an user account per technical key instead of using an email-address. Such a technical key ensures an exact identification of an user account without giving detailed information for possible missusage. Additionally the Gradido-ID allows to administrade any user account data like changing the email address or define several email addresses without any side effects on the identification of the user account. @@ -22,12 +22,12 @@ The second step is to decribe all concerning business logic processes, which hav The entity users has to be changed by adding the following columns. -| Column | Type | Description | -| ------------------------ | ------ | -------------------------------------------------------------------------------------- | -| gradidoID | String | technical unique key of the user as UUID (version 4) | -| alias | String | a business unique key of the user | -| passphraseEncryptionType | int | defines the type of encrypting the passphrase: 1 = email (default), 2 = gradidoID, ... | -| emailID | int | technical foreign key to the new entity Contact | +| Column | Type | Description | +| ------------------------ | ------ | ----------------------------------------------------------------------------------------------------------------- | +| gradidoID | String | technical unique key of the user as UUID (version 4) | +| alias | String | a business unique key of the user | +| passphraseEncryptionType | int | defines the type of encrypting the passphrase: 1 = email (default), 2 = gradidoID, ... | +| emailID | int | technical foreign key to the entry with type Email and contactChannel=maincontact of the new entity UserContacts | ##### Email vs emailID @@ -39,14 +39,21 @@ The preferred and proper solution will be to add a new column `Users.emailId `as A new entity `UserContacts `is introduced to store several contacts of different types like email, telephone or other kinds of contact addresses. -| Column | Type | Description | -| --------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| id | int | the technical key of a contact entity | -| type | int | Defines the type of contact entry as enum: Email, Phone, etc | -| usersID | int | Defines the foreign key to the `Users` table | -| email | String | defines the address of a contact entry of type Email | -| phone | String | defines the address of a contact entry of type Phone | -| contactChannels | String | define the contact channel as comma separated list for which this entry is confirmed by the user e.g. main contact (default), infomail, contracting, advertisings, ... | +| Column | Type | Description | +| --------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| id | int | the technical key of a contact entity | +| type | int | Defines the type of contact entry as enum: Email, Phone, etc | +| userID | int | Defines the foreign key to the `Users` table | +| email | String | defines the address of a contact entry of type Email | +| emailVerificationCode | unsinged bigint(20) | unique code to verify email or password reset | +| emailOptInType | int | REGISTER=1, RESET_PASSWORD=2 | +| emailResendCount | int | counter how often the email was resend | +| emailChecked | boolean | flag if email is verified and confirmed | +| createdAt | DateTime | point of time the Contact was created | +| updatedAt | DateTime | point of time the Contact was updated | +| deletedAt | DateTime | point of time the Contact was soft deleted | +| phone | String | defines the address of a contact entry of type Phone | +| contactChannels | String | define the contact channel as comma separated list for which this entry is confirmed by the user e.g. main contact (default), infomail, contracting, advertisings, ... | ### Database-Migration @@ -58,18 +65,24 @@ In a one-time migration create for each entry of the `Users `tabel an unique UUI #### Primary Email Contact -In a one-time migration read for each entry of the `Users `table the `Users.id` and `Users.email` and create for it a new entry in the `UsersContact `table, by initializing the contact-values with: +In a one-time migration read for each entry of the `Users `table the `Users.id` and `Users.email`, select from the table `login_email_opt_in` the entry with the `login_email_opt_in.user_id` = `Users.id` and create a new entry in the `UsersContact `table, by initializing the contact-values with: * id = new technical key * type = Enum-Email * userID = `Users.id` * email = `Users.email` +* emailVerifyCode = `login_email_opt_in.verification_code` +* emailOptInType = `login_email_opt_in.email_opt_in_type_id` +* emailResendCount = `login_email_opt_in.resent_count` +* emailChecked = `Users.emailChecked` +* createdAt = `login_email_opt_in.created_at` +* updatedAt = `login_email_opt_in.updated_at` * phone = null * usedChannel = Enum-"main contact" and update the `Users `entry with `Users.emailId = UsersContact.Id` and `Users.passphraseEncryptionType = 1` -After this one-time migration the column `Users.email` can be deleted. +After this one-time migration and a verification, which ensures that all data are migrated, then the columns `Users.email`, `Users.emailChecked`, `Users.emailHash` and the table `login_email_opt_in` can be deleted. ### Adaption of BusinessLogic @@ -109,7 +122,7 @@ The logic of change password has to be adapted by * read the users email address from the `UsersContact `table * give the email address as input for the password decryption of the existing password - * use the `Users.userID` as input for the password encryption fo the new password + * use the `Users.userID` as input for the password encryption for the new password * change the `Users.passphraseEnrycptionType` to the new value =2 * if the `Users.passphraseEncryptionType` = 2, then @@ -129,11 +142,17 @@ A new logic has to be introduced to search the user identity per different input A new mapping logic will be necessary to allow using unmigrated APIs like GDT-servers api. So it must be possible to give this identity-mapping logic the following input to get the respective output: * email -> userID +* email -> gradidoID * email -> alias +* userID -> gradidoID * userID -> email * userID -> alias +* alias -> gradidoID * alias -> email * alias -> userID +* gradidoID -> email +* gradidoID -> userID +* gradidoID -> alias #### GDT-Access diff --git a/e2e-tests/README.md b/e2e-tests/README.md new file mode 100644 index 000000000..f53618ab4 --- /dev/null +++ b/e2e-tests/README.md @@ -0,0 +1,7 @@ +# Gradido end-to-end tests + +This is still WIP. + +For automated end-to-end testing one of the frameworks Cypress or Playwright will be utilized. + +For more details on how to run them, see the subfolders' README instructions. diff --git a/e2e-tests/cypress/.gitignore b/e2e-tests/cypress/.gitignore new file mode 100644 index 000000000..7dfc547b4 --- /dev/null +++ b/e2e-tests/cypress/.gitignore @@ -0,0 +1,4 @@ +tests/node_modules/ +tests/cypress/screenshots/ +tests/cypress/videos/ +tests/cucumber-messages.ndjson diff --git a/e2e-tests/cypress/Dockerfile b/e2e-tests/cypress/Dockerfile new file mode 100644 index 000000000..8c8e00da8 --- /dev/null +++ b/e2e-tests/cypress/Dockerfile @@ -0,0 +1,36 @@ +############################################################################### +# Dockerfile to create a ready-to-use Cypress Docker image for end-to-end +# testing. +# +# Based on the images containing several browsers, provided by Cypress.io +# (https://github.com/cypress-io/cypress-docker-images/tree/master/browsers) +# this Dockerfile is based a slim Linux Dockerfile using Node.js 16.14.2. +# +# Here the latest stable versions of the browsers Chromium and Firefox are +# installed before installing Cypress. +############################################################################### +FROM cypress/base:16.14.2-slim + +ARG DOCKER_WORKDIR=/tests/ +WORKDIR $DOCKER_WORKDIR + +# install dependencies +RUN apt-get -qq update > /dev/null && \ + apt-get -qq install -y bzip2 mplayer wget > /dev/null + +# install Chromium browser +RUN apt-get -qq install -y chromium > /dev/null + +# install Firefox browser +RUN wget --no-verbose -O /tmp/firefox.tar.bz2 "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" && \ + tar -C /opt -xjf /tmp/firefox.tar.bz2 && \ + rm /tmp/firefox.tar.bz2 && \ + ln -fs /opt/firefox/firefox /usr/bin/firefox + +# clean up +RUN rm -rf /var/lib/apt/lists/* && apt-get -qq clean > /dev/null + +COPY tests/package.json tests/yarn.lock $DOCKER_WORKDIR + +RUN yarn install +COPY tests/ $DOCKER_WORKDIR diff --git a/e2e-tests/cypress/README.md b/e2e-tests/cypress/README.md new file mode 100644 index 000000000..b1ddae514 --- /dev/null +++ b/e2e-tests/cypress/README.md @@ -0,0 +1,24 @@ +# Gradido End-to-End Testing with [Cypress](https://www.cypress.io/) (CI-ready via Docker) + + +A sample setup to show-case Cypress as an end-to-end testing tool for Gradido running in a Docker container. +Here we have a simple UI-based happy path login test running against the DEV system. + +## Precondition +Since dependencies and configurations for Github Actions integration is not set up yet, please run in root directory + +```bash +docker-compose up +``` + +to boot up the DEV system, before running the test. + +## Execute the test + +```bash +# build a Docker image from the Dockerfile +docker build -t gradido_e2e-tests-cypress . + +# run the Docker container and execute the given tests +docker run -it --network=host gradido_e2e-tests-cypress yarn run cypress-e2e-tests +``` diff --git a/e2e-tests/cypress/tests/.eslintignore b/e2e-tests/cypress/tests/.eslintignore new file mode 100644 index 000000000..3c3629e64 --- /dev/null +++ b/e2e-tests/cypress/tests/.eslintignore @@ -0,0 +1 @@ +node_modules diff --git a/e2e-tests/cypress/tests/.eslintrc.js b/e2e-tests/cypress/tests/.eslintrc.js new file mode 100644 index 000000000..157454287 --- /dev/null +++ b/e2e-tests/cypress/tests/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + root: true, + env: { + node: true, + }, + parser: "@typescript-eslint/parser", + plugins: ["cypress", "prettier", "@typescript-eslint"], + extends: [ + "standard", + "eslint:recommended", + "plugin:prettier/recommended", + "plugin:@typescript-eslint/recommended", + ], + rules: { + "no-console": ["error"], + "no-debugger": "error", + "prettier/prettier": [ + "error", + { + htmlWhitespaceSensitivity: "ignore", + }, + ], + }, +}; diff --git a/e2e-tests/cypress/tests/cypress.config.ts b/e2e-tests/cypress/tests/cypress.config.ts new file mode 100644 index 000000000..815394c5e --- /dev/null +++ b/e2e-tests/cypress/tests/cypress.config.ts @@ -0,0 +1,64 @@ +import { defineConfig } from "cypress"; +import { addCucumberPreprocessorPlugin } from "@badeball/cypress-cucumber-preprocessor"; +import browserify from "@badeball/cypress-cucumber-preprocessor/browserify"; + +async function setupNodeEvents( + on: Cypress.PluginEvents, + config: Cypress.PluginConfigOptions +): Promise { + await addCucumberPreprocessorPlugin(on, config); + + on( + "file:preprocessor", + browserify(config, { + typescript: require.resolve("typescript"), + }) + ); + + on("after:run", (results) => { + if (results) { + // results will be undefined in interactive mode + // eslint-disable-next-line no-console + console.log(results.status); + } + }); + + return config; +} + +export default defineConfig({ + e2e: { + specPattern: "**/*.feature", + excludeSpecPattern: "*.js", + baseUrl: "http://localhost:3000", + chromeWebSecurity: false, + supportFile: "cypress/support/index.ts", + viewportHeight: 720, + viewportWidth: 1280, + retries: { + runMode: 2, + openMode: 0, + }, + env: { + backendURL: "http://localhost:4000", + loginQuery: `query ($email: String!, $password: String!, $publisherId: Int) { + login(email: $email, password: $password, publisherId: $publisherId) { + email + firstName + lastName + language + klickTipp { + newsletterState + __typename + } + hasElopage + publisherId + isAdmin + creation + __typename + } +}`, + }, + setupNodeEvents, + }, +}); diff --git a/e2e-tests/cypress/tests/cypress/e2e/User.Authentication.feature b/e2e-tests/cypress/tests/cypress/e2e/User.Authentication.feature new file mode 100644 index 000000000..e2c459692 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/e2e/User.Authentication.feature @@ -0,0 +1,17 @@ +Feature: User authentication + As a user + I want to be able to sign in - only with valid credentials + In order to be able to posts and do other contributions as myself + Furthermore I want to be able to stay logged in and logout again + + # TODO for these pre-conditions utilize seeding or API check, if user exists in test system + # Background: + # Given the following "users" are in the database: + # | email | password | name | + # | bibi@bloxberg.de | Aa12345_ | Bibi Bloxberg | + + Scenario: Log in successfully + Given the browser navigates to page "/login" + When the user submits the credentials "bibi@bloxberg.de" "Aa12345_" + Then the user is logged in with username "Bibi Bloxberg" + diff --git a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword.feature b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword.feature new file mode 100644 index 000000000..ceee131fb --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword.feature @@ -0,0 +1,27 @@ +Feature: User profile - change password + As a user + I want the option to change my password on my profile page. + + Background: + # TODO for these pre-conditions utilize seeding or API check, if user exists in test system + # Given the following "users" are in the database: + # | email | password | name | + # | bibi@bloxberg.de | Aa12345_ | Bibi Bloxberg | | + + # TODO instead of credentials use the name of an user object (see seeds in backend) + Given the user is logged in as "bibi@bloxberg.de" "Aa12345_" + + Scenario: Change password successfully + Given the browser navigates to page "/profile" + And the user opens the change password menu + When the user fills the password form with: + | Old password | Aa12345_ | + | New password | 12345Aa_ | + | Repeat new password | 12345Aa_ | + And the user submits the password form + And the user is presented a "success" message + And the user logs out + Then the user submits the credentials "bibi@bloxberg.de" "Aa12345_" + And the user cannot login + But the user submits the credentials "bibi@bloxberg.de" "12345Aa_" + And the user is logged in with username "Bibi Bloxberg" diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts b/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts new file mode 100644 index 000000000..a16b93a11 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts @@ -0,0 +1,30 @@ +/// + +export class LoginPage { + // selectors + emailInput = "#Email-input-field"; + passwordInput = "#Password-input-field"; + submitBtn = "[type=submit]"; + emailHint = "#vee_Email"; + passwordHint = "#vee_Password"; + + goto() { + cy.visit("/"); + return this; + } + + enterEmail(email: string) { + cy.get(this.emailInput).clear().type(email); + return this; + } + + enterPassword(password: string) { + cy.get(this.passwordInput).clear().type(password); + return this; + } + + submitLogin() { + cy.get(this.submitBtn).click(); + return this; + } +} diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/OverviewPage.ts b/e2e-tests/cypress/tests/cypress/e2e/models/OverviewPage.ts new file mode 100644 index 000000000..426c2b8b3 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/e2e/models/OverviewPage.ts @@ -0,0 +1,10 @@ +/// + +export class OverviewPage { + navbarName = '[data-test="navbar-item-username"]'; + + goto() { + cy.visit("/overview"); + return this; + } +} diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts b/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts new file mode 100644 index 000000000..b280a0b2a --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts @@ -0,0 +1,35 @@ +/// + +export class ProfilePage { + // selectors + openChangePassword = "[data-test=open-password-change-form]"; + oldPasswordInput = "#password-input-field"; + newPasswordInput = "#New-password-input-field"; + newPasswordRepeatInput = "#Repeat-new-password-input-field"; + submitNewPasswordBtn = "[data-test=submit-new-password-btn]"; + + goto() { + cy.visit("/profile"); + return this; + } + + enterOldPassword(password: string) { + cy.get(this.oldPasswordInput).clear().type(password); + return this; + } + + enterNewPassword(password: string) { + cy.get(this.newPasswordInput).clear().type(password); + return this; + } + + enterRepeatPassword(password: string) { + cy.get(this.newPasswordRepeatInput).clear().type(password); + return this; + } + + submitPasswordForm() { + cy.get(this.submitNewPasswordBtn).click(); + return this; + } +} diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/SideNavMenu.ts b/e2e-tests/cypress/tests/cypress/e2e/models/SideNavMenu.ts new file mode 100644 index 000000000..3dd9d6914 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/e2e/models/SideNavMenu.ts @@ -0,0 +1,17 @@ +/// + +export class SideNavMenu { + // selectors + profileMenu = "[data-test=profile-menu]"; + logoutMenu = "[data-test=logout-menu]"; + + openUserProfile() { + cy.get(this.profileMenu).click(); + return this; + } + + logout() { + cy.get(this.logoutMenu).click(); + return this; + } +} diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts b/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts new file mode 100644 index 000000000..b2198bc8d --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts @@ -0,0 +1,7 @@ +/// + +export class Toasts { + // selectors + toastTitle = ".gdd-toaster-title"; + toastMessage = ".gdd-toaster-body"; +} diff --git a/e2e-tests/cypress/tests/cypress/fixtures/users.json b/e2e-tests/cypress/tests/cypress/fixtures/users.json new file mode 100644 index 000000000..f13e203f0 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/fixtures/users.json @@ -0,0 +1,7 @@ +{ + "user": { + "email": "bibi@bloxberg.de", + "password": "Aa12345_", + "name": "Bibi Bloxberg" + } +} diff --git a/e2e-tests/cypress/tests/cypress/support/e2e.ts b/e2e-tests/cypress/tests/cypress/support/e2e.ts new file mode 100644 index 000000000..16cc474bf --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/e2e.ts @@ -0,0 +1,38 @@ +import jwtDecode from "jwt-decode"; + +Cypress.Commands.add("login", (email, password) => { + cy.clearLocalStorage("vuex"); + + cy.request({ + method: "POST", + url: Cypress.env("backendURL"), + body: { + operationName: null, + variables: { + email: email, + password: password, + }, + query: Cypress.env("loginQuery"), + }, + }).then(async (response) => { + const token = response.headers.token; + let tokenTime; + + // to avoid JWT InvalidTokenError, the decoding of the token is wrapped + // in a try-catch block (see + // https://github.com/auth0/jwt-decode/issues/65#issuecomment-395493807) + try { + tokenTime = jwtDecode(token).exp; + } catch (tokenDecodingError) { + cy.log("JWT decoding error: ", tokenDecodingError); + } + + const vuexToken = { + token: token, + tokenTime: tokenTime, + }; + + cy.visit("/"); + window.localStorage.setItem("vuex", JSON.stringify(vuexToken)); + }); +}); diff --git a/e2e-tests/cypress/tests/cypress/support/index.ts b/e2e-tests/cypress/tests/cypress/support/index.ts new file mode 100644 index 000000000..99ab0efc2 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/index.ts @@ -0,0 +1,14 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +/// + +import "./e2e"; + +declare global { + namespace Cypress { + interface Chainable { + login(email: string, password: string): Chainable; + } + } +} diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts new file mode 100644 index 000000000..439974cda --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts @@ -0,0 +1,52 @@ +import { Given, Then, When } from "@badeball/cypress-cucumber-preprocessor"; +import { LoginPage } from "../../e2e/models/LoginPage"; +import { OverviewPage } from "../../e2e/models/OverviewPage"; +import { SideNavMenu } from "../../e2e/models/SideNavMenu"; +import { Toasts } from "../../e2e/models/Toasts"; + +Given("the browser navigates to page {string}", (page: string) => { + cy.visit(page); +}); + +// login-related + +Given( + "the user is logged in as {string} {string}", + (email: string, password: string) => { + cy.login(email, password); + } +); + +Then("the user is logged in with username {string}", (username: string) => { + const overviewPage = new OverviewPage(); + cy.url().should("include", "/overview"); + cy.get(overviewPage.navbarName).should("contain", username); +}); + +Then("the user cannot login", () => { + const toast = new Toasts(); + cy.get(toast.toastTitle).should("contain.text", "Error!"); + cy.get(toast.toastMessage).should( + "contain.text", + "No user with this credentials." + ); +}); + +// + +When( + "the user submits the credentials {string} {string}", + (email: string, password: string) => { + const loginPage = new LoginPage(); + loginPage.enterEmail(email); + loginPage.enterPassword(password); + loginPage.submitLogin(); + } +); + +// logout + +Then("the user logs out", () => { + const sideNavMenu = new SideNavMenu(); + sideNavMenu.logout(); +}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/user_authentication_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_authentication_steps.ts new file mode 100644 index 000000000..1e5cfe88c --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_authentication_steps.ts @@ -0,0 +1,7 @@ +import { When } from "@badeball/cypress-cucumber-preprocessor"; +import { LoginPage } from "../../e2e/models/LoginPage"; + +When("the user submits no credentials", () => { + const loginPage = new LoginPage(); + loginPage.submitLogin(); +}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts new file mode 100644 index 000000000..cbe851f02 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts @@ -0,0 +1,32 @@ +import { And, When } from "@badeball/cypress-cucumber-preprocessor"; +import { ProfilePage } from "../../e2e/models/ProfilePage"; +import { Toasts } from "../../e2e/models/Toasts"; + +const profilePage = new ProfilePage(); + +And("the user opens the change password menu", () => { + cy.get(profilePage.openChangePassword).click(); + cy.get(profilePage.newPasswordRepeatInput).should("be.visible"); + cy.get(profilePage.submitNewPasswordBtn).should("be.disabled"); +}); + +When("the user fills the password form with:", (table) => { + table = table.rowsHash(); + profilePage.enterOldPassword(table["Old password"]); + profilePage.enterNewPassword(table["New password"]); + profilePage.enterRepeatPassword(table["Repeat new password"]); + cy.get(profilePage.submitNewPasswordBtn).should("be.enabled"); +}); + +And("the user submits the password form", () => { + profilePage.submitPasswordForm(); +}); + +When("the user is presented a {string} message", (type: string) => { + const toast = new Toasts(); + cy.get(toast.toastTitle).should("contain.text", "Success"); + cy.get(toast.toastMessage).should( + "contain.text", + "Your password has been changed." + ); +}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/user_registration_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_registration_steps.ts new file mode 100644 index 000000000..49e121fc2 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_registration_steps.ts @@ -0,0 +1,24 @@ +import { And, When } from "@badeball/cypress-cucumber-preprocessor"; +import { RegistrationPage } from "../../e2e/models/RegistrationPage"; + +const registrationPage = new RegistrationPage(); + +When( + "the user fills name and email {string} {string} {string}", + (firstname: string, lastname: string, email: string) => { + const registrationPage = new RegistrationPage(); + registrationPage.enterFirstname(firstname); + registrationPage.enterLastname(lastname); + registrationPage.enterEmail(email); + } +); + +And("the user agrees to the privacy policy", () => { + registrationPage.checkPrivacyCheckbox(); +}); + +And("the user submits the registration form", () => { + registrationPage.submitRegistrationPage(); + cy.get(registrationPage.RegistrationThanxHeadline).should("be.visible"); + cy.get(registrationPage.RegistrationThanxText).should("be.visible"); +}); diff --git a/e2e-tests/cypress/tests/package.json b/e2e-tests/cypress/tests/package.json new file mode 100644 index 000000000..a9979725e --- /dev/null +++ b/e2e-tests/cypress/tests/package.json @@ -0,0 +1,39 @@ +{ + "name": "gradido-e2e-tests-cypress", + "version": "1.0.0", + "description": "End-to-end tests with Cypress", + "main": "yarn run cypress run", + "repository": "https://github.com/gradido/gradido/e2e-tests/cypress", + "author": "Mathias Lenz", + "license": "Apache-2.0", + "private": false, + "cypress-cucumber-preprocessor": { + "nonGlobalStepDefinitions": true, + "json": { + "enabled": true + } + }, + "scripts": { + "cypress": "cypress run", + "lint": "eslint --max-warnings=0 --ext .js,.ts ." + }, + "dependencies": { + "@badeball/cypress-cucumber-preprocessor": "^12.0.0", + "@cypress/browserify-preprocessor": "^3.0.2", + "@typescript-eslint/eslint-plugin": "^5.38.0", + "@typescript-eslint/parser": "^5.38.0", + "cypress": "^10.4.0", + "eslint": "^8.23.1", + "eslint-config-prettier": "^8.3.0", + "eslint-config-standard": "^16.0.3", + "eslint-loader": "^4.0.2", + "eslint-plugin-cypress": "^2.12.1", + "eslint-plugin-import": "^2.23.4", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-promise": "^5.1.0", + "jwt-decode": "^3.1.2", + "prettier": "^2.7.1", + "typescript": "^4.7.4" + } +} diff --git a/e2e-tests/cypress/tests/tsconfig.json b/e2e-tests/cypress/tests/tsconfig.json new file mode 100644 index 000000000..c031a126e --- /dev/null +++ b/e2e-tests/cypress/tests/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es2016", + "lib": ["es6", "dom"], + "baseUrl": "../node_modules", + "types": ["cypress", "node"], + "strict": true + }, + "include": ["**/*.ts"] +} diff --git a/e2e-tests/cypress/tests/yarn.lock b/e2e-tests/cypress/tests/yarn.lock new file mode 100644 index 000000000..c0f623e47 --- /dev/null +++ b/e2e-tests/cypress/tests/yarn.lock @@ -0,0 +1,5169 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.1.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== + dependencies: + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8", "@babel/compat-data@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.1.tgz#72d647b4ff6a4f82878d184613353af1dd0290f9" + integrity sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg== + +"@babel/core@^7.16.0": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.1.tgz#c8fa615c5e88e272564ace3d42fbc8b17bfeb22b" + integrity sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.19.0" + "@babel/helper-compilation-targets" "^7.19.1" + "@babel/helper-module-transforms" "^7.19.0" + "@babel/helpers" "^7.19.0" + "@babel/parser" "^7.19.1" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.1" + "@babel/types" "^7.19.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + +"@babel/generator@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.0.tgz#785596c06425e59334df2ccee63ab166b738419a" + integrity sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg== + dependencies: + "@babel/types" "^7.19.0" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb" + integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.18.6" + "@babel/types" "^7.18.9" + +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.19.0", "@babel/helper-compilation-targets@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.1.tgz#7f630911d83b408b76fe584831c98e5395d7a17c" + integrity sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg== + dependencies: + "@babel/compat-data" "^7.19.1" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.21.3" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.18.6": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz#bfd6904620df4e46470bae4850d66be1054c404b" + integrity sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz#7976aca61c0984202baca73d84e2337a5424a41b" + integrity sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.1.0" + +"@babel/helper-define-polyfill-provider@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" + integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== + dependencies: + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== + +"@babel/helper-explode-assignable-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096" + integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" + integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== + dependencies: + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" + +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-member-expression-to-functions@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815" + integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg== + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz#309b230f04e22c58c6a2c0c0c7e50b216d350c30" + integrity sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.18.6" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.0" + "@babel/types" "^7.19.0" + +"@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== + dependencies: + "@babel/types" "^7.18.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.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf" + integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw== + +"@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" + integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-wrap-function" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz#e1592a9b4b368aa6bdb8784a711e0bcbf0612b78" + integrity sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/traverse" "^7.19.1" + "@babel/types" "^7.19.0" + +"@babel/helper-simple-access@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea" + integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-skip-transparent-expression-wrappers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz#778d87b3a758d90b471e7b9918f34a9a02eb5818" + integrity sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw== + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56" + integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw== + +"@babel/helper-validator-identifier@^7.18.6": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helper-wrap-function@^7.18.9": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz#89f18335cff1152373222f76a4b37799636ae8b1" + integrity sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg== + dependencies: + "@babel/helper-function-name" "^7.19.0" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.0" + "@babel/types" "^7.19.0" + +"@babel/helpers@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.19.0.tgz#f30534657faf246ae96551d88dd31e9d1fa1fc18" + integrity sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg== + dependencies: + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.0" + "@babel/types" "^7.19.0" + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.18.10", "@babel/parser@^7.18.8", "@babel/parser@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.1.tgz#6f6d6c2e621aad19a92544cc217ed13f1aac5b4c" + integrity sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" + integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz#a11af19aa373d68d561f08e0a57242350ed0ec50" + integrity sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" + +"@babel/plugin-proposal-async-generator-functions@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz#34f6f5174b688529342288cd264f80c9ea9fb4a7" + integrity sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.16.0", "@babel/plugin-proposal-class-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-class-static-block@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz#8aa81d403ab72d3962fc06c26e222dacfc9b9020" + integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-dynamic-import@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94" + integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203" + integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b" + integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz#8148cbb350483bf6220af06fa6db3690e14b2e23" + integrity sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" + integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" + integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.16.0", "@babel/plugin-proposal-object-rest-spread@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz#f9434f6beb2c8cae9dfcf97d2a5941bbbf9ad4e7" + integrity sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q== + dependencies: + "@babel/compat-data" "^7.18.8" + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.18.8" + +"@babel/plugin-proposal-optional-catch-binding@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb" + integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz#e8e8fe0723f2563960e4bf5e9690933691915993" + integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" + integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-proposal-private-property-in-object@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz#a64137b232f0aca3733a67eb1a144c192389c503" + integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@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-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-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz#cd6190500a4fa2fe31990a963ffab4b63e4505e4" + integrity sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@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== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@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== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@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== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-arrow-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe" + integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-async-to-generator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz#ccda3d1ab9d5ced5265fdb13f1882d5476c71615" + integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-remap-async-to-generator" "^7.18.6" + +"@babel/plugin-transform-block-scoped-functions@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8" + integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-block-scoping@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz#f9b7e018ac3f373c81452d6ada8bd5a18928926d" + integrity sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-classes@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz#0e61ec257fba409c41372175e7c1e606dc79bb20" + integrity sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-compilation-targets" "^7.19.0" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz#2357a8224d402dad623caf6259b611e56aec746e" + integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-destructuring@^7.18.13": + version "7.18.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz#9e03bc4a94475d62b7f4114938e6c5c33372cbf5" + integrity sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8" + integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-duplicate-keys@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e" + integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-exponentiation-operator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd" + integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-for-of@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1" + integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-function-name@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0" + integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ== + dependencies: + "@babel/helper-compilation-targets" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc" + integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-member-expression-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e" + integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-modules-amd@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz#8c91f8c5115d2202f277549848874027d7172d21" + integrity sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz#afd243afba166cca69892e24a8fd8c9f2ca87883" + integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-simple-access" "^7.18.6" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz#5f20b471284430f02d9c5059d9b9a16d4b085a1f" + integrity sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A== + dependencies: + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-module-transforms" "^7.19.0" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-validator-identifier" "^7.18.6" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9" + integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ== + dependencies: + "@babel/helper-module-transforms" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz#ec7455bab6cd8fb05c525a94876f435a48128888" + integrity sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.19.0" + "@babel/helper-plugin-utils" "^7.19.0" + +"@babel/plugin-transform-new-target@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8" + integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-object-super@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c" + integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.6" + +"@babel/plugin-transform-parameters@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a" + integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-property-literals@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3" + integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-display-name@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" + integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-react-jsx-development@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" + integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== + dependencies: + "@babel/plugin-transform-react-jsx" "^7.18.6" + +"@babel/plugin-transform-react-jsx@^7.18.6": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.19.0.tgz#b3cbb7c3a00b92ec8ae1027910e331ba5c500eb9" + integrity sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-jsx" "^7.18.6" + "@babel/types" "^7.19.0" + +"@babel/plugin-transform-react-pure-annotations@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844" + integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-regenerator@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73" + integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + regenerator-transform "^0.15.0" + +"@babel/plugin-transform-reserved-words@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a" + integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-runtime@^7.16.0": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz#a3df2d7312eea624c7889a2dcd37fd1dfd25b2c6" + integrity sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA== + dependencies: + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-plugin-utils" "^7.19.0" + babel-plugin-polyfill-corejs2 "^0.3.3" + babel-plugin-polyfill-corejs3 "^0.6.0" + babel-plugin-polyfill-regenerator "^0.4.1" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" + integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-spread@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz#dd60b4620c2fec806d60cfaae364ec2188d593b6" + integrity sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w== + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" + +"@babel/plugin-transform-sticky-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc" + integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-template-literals@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e" + integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-typeof-symbol@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0" + integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-escapes@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz#1ecfb0eda83d09bbcb77c09970c2dd55832aa246" + integrity sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ== + dependencies: + "@babel/helper-plugin-utils" "^7.18.9" + +"@babel/plugin-transform-unicode-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca" + integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/preset-env@^7.16.0": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.19.1.tgz#9f04c916f9c0205a48ebe5cc1be7768eb1983f67" + integrity sha512-c8B2c6D16Lp+Nt6HcD+nHl0VbPKVnNPTpszahuxJJnurfMtKeZ80A+qUv48Y7wqvS+dTFuLuaM9oYxyNHbCLWA== + dependencies: + "@babel/compat-data" "^7.19.1" + "@babel/helper-compilation-targets" "^7.19.1" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-async-generator-functions" "^7.19.1" + "@babel/plugin-proposal-class-properties" "^7.18.6" + "@babel/plugin-proposal-class-static-block" "^7.18.6" + "@babel/plugin-proposal-dynamic-import" "^7.18.6" + "@babel/plugin-proposal-export-namespace-from" "^7.18.9" + "@babel/plugin-proposal-json-strings" "^7.18.6" + "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" + "@babel/plugin-proposal-numeric-separator" "^7.18.6" + "@babel/plugin-proposal-object-rest-spread" "^7.18.9" + "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" + "@babel/plugin-proposal-optional-chaining" "^7.18.9" + "@babel/plugin-proposal-private-methods" "^7.18.6" + "@babel/plugin-proposal-private-property-in-object" "^7.18.6" + "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.18.6" + "@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" + "@babel/plugin-transform-arrow-functions" "^7.18.6" + "@babel/plugin-transform-async-to-generator" "^7.18.6" + "@babel/plugin-transform-block-scoped-functions" "^7.18.6" + "@babel/plugin-transform-block-scoping" "^7.18.9" + "@babel/plugin-transform-classes" "^7.19.0" + "@babel/plugin-transform-computed-properties" "^7.18.9" + "@babel/plugin-transform-destructuring" "^7.18.13" + "@babel/plugin-transform-dotall-regex" "^7.18.6" + "@babel/plugin-transform-duplicate-keys" "^7.18.9" + "@babel/plugin-transform-exponentiation-operator" "^7.18.6" + "@babel/plugin-transform-for-of" "^7.18.8" + "@babel/plugin-transform-function-name" "^7.18.9" + "@babel/plugin-transform-literals" "^7.18.9" + "@babel/plugin-transform-member-expression-literals" "^7.18.6" + "@babel/plugin-transform-modules-amd" "^7.18.6" + "@babel/plugin-transform-modules-commonjs" "^7.18.6" + "@babel/plugin-transform-modules-systemjs" "^7.19.0" + "@babel/plugin-transform-modules-umd" "^7.18.6" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" + "@babel/plugin-transform-new-target" "^7.18.6" + "@babel/plugin-transform-object-super" "^7.18.6" + "@babel/plugin-transform-parameters" "^7.18.8" + "@babel/plugin-transform-property-literals" "^7.18.6" + "@babel/plugin-transform-regenerator" "^7.18.6" + "@babel/plugin-transform-reserved-words" "^7.18.6" + "@babel/plugin-transform-shorthand-properties" "^7.18.6" + "@babel/plugin-transform-spread" "^7.19.0" + "@babel/plugin-transform-sticky-regex" "^7.18.6" + "@babel/plugin-transform-template-literals" "^7.18.9" + "@babel/plugin-transform-typeof-symbol" "^7.18.9" + "@babel/plugin-transform-unicode-escapes" "^7.18.10" + "@babel/plugin-transform-unicode-regex" "^7.18.6" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.19.0" + babel-plugin-polyfill-corejs2 "^0.3.3" + babel-plugin-polyfill-corejs3 "^0.6.0" + babel-plugin-polyfill-regenerator "^0.4.1" + core-js-compat "^3.25.1" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.16.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" + integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-validator-option" "^7.18.6" + "@babel/plugin-transform-react-display-name" "^7.18.6" + "@babel/plugin-transform-react-jsx" "^7.18.6" + "@babel/plugin-transform-react-jsx-development" "^7.18.6" + "@babel/plugin-transform-react-pure-annotations" "^7.18.6" + +"@babel/runtime@^7.16.0", "@babel/runtime@^7.8.4": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259" + integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.18.10": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + +"@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.1.tgz#0fafe100a8c2a603b4718b1d9bf2568d1d193347" + integrity sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.19.0" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.19.1" + "@babel/types" "^7.19.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.4.4": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.0.tgz#75f21d73d73dc0351f3368d28db73465f4814600" + integrity sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA== + dependencies: + "@babel/helper-string-parser" "^7.18.10" + "@babel/helper-validator-identifier" "^7.18.6" + to-fast-properties "^2.0.0" + +"@badeball/cypress-configuration@^4.0.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@badeball/cypress-configuration/-/cypress-configuration-4.2.0.tgz#4c19bada0e40600b572b4d91933e0bd226cb2e3f" + integrity sha512-8Dc6diBW8zUycpCFbr7vqQ8ioNZMvpHV79KGdHVpwpRtkFX6enwG82CKU9DeWys6Ou5dFpXw6NYNYNb46y7UYA== + dependencies: + "@babel/parser" "^7.18.8" + debug "^4.3.2" + esbuild "^0.14.23" + glob "^7.1.6" + minimatch "^3.0.4" + node-hook "^1.0.0" + +"@badeball/cypress-cucumber-preprocessor@^12.0.0": + version "12.2.0" + resolved "https://registry.yarnpkg.com/@badeball/cypress-cucumber-preprocessor/-/cypress-cucumber-preprocessor-12.2.0.tgz#1702bbc2a10b40c7e90f10bd1840761a86c7ecc9" + integrity sha512-XSuZl4eWMcfq8rauhUnvgbNeKiDLKfaR87huj9VwPAhfIc2cRHNHCiXCasB7ci99McGaudqLqu2QsfZMStTVag== + dependencies: + "@badeball/cypress-configuration" "^4.0.0" + "@cucumber/cucumber-expressions" "^16.0.0" + "@cucumber/gherkin" "^24.0.0" + "@cucumber/html-formatter" "^19.2.0" + "@cucumber/message-streams" "^4.0.1" + "@cucumber/messages" "^19.1.2" + "@cucumber/tag-expressions" "^4.1.0" + base64-js "^1.5.1" + chalk "^4.1.2" + common-ancestor-path "^1.0.1" + cosmiconfig "^7.0.1" + debug "^4.2.0" + glob "^7.2.0" + is-path-inside "^3.0.3" + resolve-pkg "^2.0.0" + uuid "^8.3.2" + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@cucumber/cucumber-expressions@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/cucumber-expressions/-/cucumber-expressions-16.0.0.tgz#f8bc43da26f12db8f0d74ff3031a881e4fa4516d" + integrity sha512-HTh+Pg7oQ5aLuCkSbD2Q6jBaE40M3R/XaLEz+UqD5d9dZRu6P38W4LTooV5bV6dZgBunlMLK8+6ug2ziYvRddw== + dependencies: + regexp-match-indices "1.0.2" + +"@cucumber/gherkin@^24.0.0": + version "24.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin/-/gherkin-24.0.0.tgz#b0d2ab328caa5357491f1117c31195d3e545da0c" + integrity sha512-b7OsnvX1B8myDAKMc+RAiUX9bzgtNdjGsiMj10O13xu2HBWIOQ19EqBJ4xLO5CFG/lGk1J/+L0lANQVowxLVBg== + dependencies: + "@cucumber/messages" "^19.0.0" + +"@cucumber/html-formatter@^19.2.0": + version "19.2.0" + resolved "https://registry.yarnpkg.com/@cucumber/html-formatter/-/html-formatter-19.2.0.tgz#47b9fcb58fbb48d0e6124fd2e867d9c6fe299470" + integrity sha512-qGms4588jmVF/G3fTbgZvxn6OQw9GaTFV007nZZ9/10M9DfrgRqjFjVxVI9TPV63xOLPicEVoqsKZtcECbdMSA== + +"@cucumber/message-streams@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@cucumber/message-streams/-/message-streams-4.0.1.tgz#a5339d3504594bb2edb5732aaae94dddb24d0970" + integrity sha512-Kxap9uP5jD8tHUZVjTWgzxemi/0uOsbGjd4LBOSxcJoOCRbESFwemUzilJuzNTB8pcTQUh8D5oudUyxfkJOKmA== + +"@cucumber/messages@^19.0.0", "@cucumber/messages@^19.1.2": + version "19.1.3" + resolved "https://registry.yarnpkg.com/@cucumber/messages/-/messages-19.1.3.tgz#c7627bd3cb924a079788a1498f8f8dd4faaa5a08" + integrity sha512-kPbAP+F8rjybdqJEK4+5D25vW9YhbhAbbyB5Qt/q8LueW50FgFnjBJba4WFizhKnVo3fs/3MgWF2DupLDQDefg== + dependencies: + "@types/uuid" "8.3.4" + class-transformer "0.5.1" + reflect-metadata "0.1.13" + uuid "8.3.2" + +"@cucumber/tag-expressions@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/tag-expressions/-/tag-expressions-4.1.0.tgz#9a91b0e0dd2f2ba703e3038c52b49b9ac06c2c6f" + integrity sha512-chTnjxV3vryL75N90wJIMdMafXmZoO2JgNJLYpsfcALL2/IQrRiny3vM9DgD5RDCSt1LNloMtb7rGey9YWxCsA== + +"@cypress/browserify-preprocessor@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.2.tgz#1dbecae394937aed47a3524cad47086c2ded8c50" + integrity sha512-y6mlFR+IR2cqcm3HabSp7AEcX9QfF1EUL4eOaw/7xexdhmdQU8ez6piyRopZQob4BK8oKTsc9PkupsU2rzjqMA== + dependencies: + "@babel/core" "^7.16.0" + "@babel/plugin-proposal-class-properties" "^7.16.0" + "@babel/plugin-proposal-object-rest-spread" "^7.16.0" + "@babel/plugin-transform-runtime" "^7.16.0" + "@babel/preset-env" "^7.16.0" + "@babel/preset-react" "^7.16.0" + "@babel/runtime" "^7.16.0" + babel-plugin-add-module-exports "^1.0.4" + babelify "^10.0.0" + bluebird "^3.7.2" + browserify "^16.2.3" + coffeeify "^3.0.1" + coffeescript "^1.12.7" + debug "^4.3.2" + fs-extra "^9.0.0" + lodash.clonedeep "^4.5.0" + through2 "^2.0.0" + watchify "^4.0.0" + +"@cypress/request@^2.88.10": + version "2.88.10" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce" + integrity sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + http-signature "~1.3.6" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^8.3.2" + +"@cypress/xvfb@^1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.2.4.tgz#2daf42e8275b39f4aa53c14214e557bd14e7748a" + integrity sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q== + dependencies: + debug "^3.1.0" + lodash.once "^4.1.1" + +"@esbuild/linux-loong64@0.14.54": + version "0.14.54" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028" + integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw== + +"@eslint/eslintrc@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.2.tgz#58b69582f3b7271d8fa67fe5251767a5b38ea356" + integrity sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.4.0" + globals "^13.15.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" + +"@humanwhocodes/config-array@^0.10.4": + version "0.10.4" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.4.tgz#01e7366e57d2ad104feea63e72248f22015c520c" + integrity sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/gitignore-to-minimatch@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz#316b0a63b91c10e53f242efb4ace5c3b34e8728d" + integrity sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA== + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/set-array@^1.0.0", "@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/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.15" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" + integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== + 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": + 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" + +"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== + +"@types/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/node@*": + version "18.7.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154" + integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg== + +"@types/node@^14.14.31": + version "14.18.29" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.29.tgz#a0c58d67a42f8953c13d32f0acda47ed26dfce40" + integrity sha512-LhF+9fbIX4iPzhsRLpK5H7iPdvW8L4IwGciXQIOEcuF62+9nw/VQVsOViAOOGxY3OlOKGLFv0sWwJXdwQeTn6A== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/sinonjs__fake-timers@8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" + integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== + +"@types/sizzle@^2.3.2": + version "2.3.3" + resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef" + integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ== + +"@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/yauzl@^2.9.1": + version "2.10.0" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599" + integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw== + dependencies: + "@types/node" "*" + +"@typescript-eslint/eslint-plugin@^5.38.0": + version "5.38.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.38.0.tgz#ac919a199548861012e8c1fb2ec4899ac2bc22ae" + integrity sha512-GgHi/GNuUbTOeoJiEANi0oI6fF3gBQc3bGFYj40nnAPCbhrtEDf2rjBmefFadweBmO1Du1YovHeDP2h5JLhtTQ== + dependencies: + "@typescript-eslint/scope-manager" "5.38.0" + "@typescript-eslint/type-utils" "5.38.0" + "@typescript-eslint/utils" "5.38.0" + debug "^4.3.4" + ignore "^5.2.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.38.0": + version "5.38.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.38.0.tgz#5a59a1ff41a7b43aacd1bb2db54f6bf1c02b2ff8" + integrity sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA== + dependencies: + "@typescript-eslint/scope-manager" "5.38.0" + "@typescript-eslint/types" "5.38.0" + "@typescript-eslint/typescript-estree" "5.38.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.38.0": + version "5.38.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.38.0.tgz#8f0927024b6b24e28671352c93b393a810ab4553" + integrity sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA== + dependencies: + "@typescript-eslint/types" "5.38.0" + "@typescript-eslint/visitor-keys" "5.38.0" + +"@typescript-eslint/type-utils@5.38.0": + version "5.38.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.38.0.tgz#c8b7f681da825fcfc66ff2b63d70693880496876" + integrity sha512-iZq5USgybUcj/lfnbuelJ0j3K9dbs1I3RICAJY9NZZpDgBYXmuUlYQGzftpQA9wC8cKgtS6DASTvF3HrXwwozA== + dependencies: + "@typescript-eslint/typescript-estree" "5.38.0" + "@typescript-eslint/utils" "5.38.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.38.0": + version "5.38.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.38.0.tgz#8cd15825e4874354e31800dcac321d07548b8a5f" + integrity sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA== + +"@typescript-eslint/typescript-estree@5.38.0": + version "5.38.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.38.0.tgz#89f86b2279815c6fb7f57d68cf9b813f0dc25d98" + integrity sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg== + dependencies: + "@typescript-eslint/types" "5.38.0" + "@typescript-eslint/visitor-keys" "5.38.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.38.0": + version "5.38.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.38.0.tgz#5b31f4896471818153790700eb02ac869a1543f4" + integrity sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.38.0" + "@typescript-eslint/types" "5.38.0" + "@typescript-eslint/typescript-estree" "5.38.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.38.0": + version "5.38.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.38.0.tgz#60591ca3bf78aa12b25002c0993d067c00887e34" + integrity sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w== + dependencies: + "@typescript-eslint/types" "5.38.0" + eslint-visitor-keys "^3.3.0" + +JSONStream@^1.0.3: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +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-node@^1.2.0, acorn-node@^1.3.0, acorn-node@^1.5.2, acorn-node@^1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" + integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== + dependencies: + acorn "^7.0.0" + acorn-walk "^7.0.0" + xtend "^4.0.2" + +acorn-walk@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.0.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.8.0: + version "8.8.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" + integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + 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-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^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@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@^3.1.0, anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arch@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + +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-includes@^3.1.4: + version "3.1.5" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.5.tgz#2c320010db8d31031fd2a5f6b3bbd4b1aad31bdb" + integrity sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + get-intrinsic "^1.1.1" + 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.flat@^1.2.5: + version "1.3.0" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz#0b0c1567bf57b38b56b4c97b8aa72ab45e4adc7b" + integrity sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.2" + es-shim-unscopables "^1.0.0" + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + +assert@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async@^3.2.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + +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== + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +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== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + +babel-plugin-add-module-exports@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.4.tgz#6caa4ddbe1f578c6a5264d4d3e6c8a2720a7ca2b" + integrity sha512-g+8yxHUZ60RcyaUpfNzy56OtWW+x9cyEe9j+CranqLiqbju2yf/Cy6ZtYK40EZxtrdHllzlVZgLmcOUCTlJ7Jg== + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-polyfill-corejs2@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" + integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-define-polyfill-provider" "^0.3.3" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" + integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + core-js-compat "^3.25.1" + +babel-plugin-polyfill-regenerator@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" + integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.3" + +babelify@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/babelify/-/babelify-10.0.0.tgz#fe73b1a22583f06680d8d072e25a1e0d1d1d7fb5" + integrity sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg== + +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.0.2, base64-js@^1.3.1, base64-js@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +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== + +blob-util@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" + integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bn.js@^4.0.0, bn.js@^4.1.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.0.0, 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== + +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" + +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== + dependencies: + fill-range "^7.0.1" + +brorand@^1.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== + +browser-pack@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.1.0.tgz#c34ba10d0b9ce162b5af227c7131c92c2ecd5774" + integrity sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA== + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.8.0" + defined "^1.0.0" + safe-buffer "^5.1.1" + through2 "^2.0.0" + umd "^3.0.0" + +browser-resolve@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-2.0.0.tgz#99b7304cb392f8d73dba741bb2d7da28c6d7842b" + integrity sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ== + dependencies: + resolve "^1.17.0" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserify-zlib@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserify@^16.2.3: + version "16.5.2" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-16.5.2.tgz#d926835e9280fa5fd57f5bc301f2ef24a972ddfe" + integrity sha512-TkOR1cQGdmXU9zW4YukWzWVSJwrxmNdADFbqbE3HFgQWe5wqZmOawqZ7J/8MPCwk/W8yY7Y0h+7mOtcZxLP23g== + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^2.0.0" + browserify-zlib "~0.2.0" + buffer "~5.2.1" + cached-path-relative "^1.0.0" + concat-stream "^1.6.0" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.0" + domain-browser "^1.2.0" + duplexer2 "~0.1.2" + events "^2.0.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "^1.0.0" + inherits "~2.0.1" + insert-module-globals "^7.0.0" + labeled-stream-splicer "^2.0.0" + mkdirp-classic "^0.5.2" + module-deps "^6.2.3" + os-browserify "~0.3.0" + parents "^1.0.1" + path-browserify "~0.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^2.0.0" + stream-http "^3.0.0" + string_decoder "^1.1.1" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "0.0.1" + url "~0.11.0" + util "~0.10.1" + vm-browserify "^1.0.0" + xtend "^4.0.0" + +browserify@^17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-17.0.0.tgz#4c48fed6c02bfa2b51fd3b670fddb805723cdc22" + integrity sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w== + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^2.0.0" + browserify-zlib "~0.2.0" + buffer "~5.2.1" + cached-path-relative "^1.0.0" + concat-stream "^1.6.0" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.1" + domain-browser "^1.2.0" + duplexer2 "~0.1.2" + events "^3.0.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "^1.0.0" + inherits "~2.0.1" + insert-module-globals "^7.2.1" + labeled-stream-splicer "^2.0.0" + mkdirp-classic "^0.5.2" + module-deps "^6.2.3" + os-browserify "~0.3.0" + parents "^1.0.1" + path-browserify "^1.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum-object "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^3.0.0" + stream-http "^3.0.0" + string_decoder "^1.1.1" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "0.0.1" + url "~0.11.0" + util "~0.12.0" + vm-browserify "^1.0.0" + xtend "^4.0.0" + +browserslist@^4.21.3, browserslist@^4.21.4: + version "4.21.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" + integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== + dependencies: + caniuse-lite "^1.0.30001400" + electron-to-chromium "^1.4.251" + node-releases "^2.0.6" + update-browserslist-db "^1.0.9" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^5.6.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@~5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" + integrity sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== + +cached-path-relative@^1.0.0, cached-path-relative@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.1.0.tgz#865576dfef39c0d6a7defde794d078f5308e3ef3" + integrity sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA== + +cachedir@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" + integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== + +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" + +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== + +caniuse-lite@^1.0.30001400: + version "1.0.30001409" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001409.tgz#6135da9dcab34cd9761d9cdb12a68e6740c5e96e" + integrity sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-more-types@^2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" + integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== + +chokidar@^3.4.0: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + 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" + +ci-info@^3.2.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.4.0.tgz#b28484fd436cbc267900364f096c9dc185efb251" + integrity sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-transformer@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-table3@~0.6.1: + version "0.6.3" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" + integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +coffeeify@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/coffeeify/-/coffeeify-3.0.1.tgz#5e2753000c50bd24c693115f33864248dd11136c" + integrity sha512-Qjnr7UX6ldK1PHV7wCnv7AuCd4q19KTUtwJnu/6JRJB4rfm12zvcXtKdacUoePOKr1I4ka/ydKiwWpNAdsQb0g== + dependencies: + convert-source-map "^1.3.0" + through2 "^2.0.0" + +coffeescript@^1.12.7: + version "1.12.7" + resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.12.7.tgz#e57ee4c4867cf7f606bfc4a0f2d550c0981ddd27" + integrity sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +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== + +colorette@^2.0.16: + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + +combine-source-map@^0.8.0, combine-source-map@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.8.0.tgz#a58d0df042c186fcf822a8e8015f5450d2d79a8b" + integrity sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg== + dependencies: + convert-source-map "~1.1.0" + inline-source-map "~0.6.0" + lodash.memoize "~3.0.3" + source-map "~0.5.3" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + 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@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +common-ancestor-path@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz#4f7d2d1394d91b7abdf51871c62f71eadb0182a7" + integrity sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w== + +common-tags@^1.8.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" + integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== + +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== + +concat-stream@^1.6.0, concat-stream@^1.6.1, concat-stream@~1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +constants-browserify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ== + +convert-source-map@^1.3.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" + integrity sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg== + +core-js-compat@^3.25.1: + version "3.25.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.2.tgz#7875573586809909c69e03ef310810c1969ee138" + integrity sha512-TxfyECD4smdn3/CjWxczVtJqVLEEC2up7/82t7vC0AzNogr+4nQ8vyF7abxAuTXWvjTClSbvGhU0RgqA4ToQaQ== + dependencies: + browserslist "^4.21.4" + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + +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== + +cosmiconfig@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^7.0.0, 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-browserify@^3.0.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +cypress@^10.4.0: + version "10.8.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.8.0.tgz#12a681f2642b6f13d636bab65d5b71abdb1497a5" + integrity sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA== + dependencies: + "@cypress/request" "^2.88.10" + "@cypress/xvfb" "^1.2.4" + "@types/node" "^14.14.31" + "@types/sinonjs__fake-timers" "8.1.1" + "@types/sizzle" "^2.3.2" + arch "^2.2.0" + blob-util "^2.0.2" + bluebird "^3.7.2" + buffer "^5.6.0" + cachedir "^2.3.0" + chalk "^4.1.0" + check-more-types "^2.24.0" + cli-cursor "^3.1.0" + cli-table3 "~0.6.1" + commander "^5.1.0" + common-tags "^1.8.0" + dayjs "^1.10.4" + debug "^4.3.2" + enquirer "^2.3.6" + eventemitter2 "6.4.7" + execa "4.1.0" + executable "^4.1.1" + extract-zip "2.0.1" + figures "^3.2.0" + fs-extra "^9.1.0" + getos "^3.2.1" + is-ci "^3.0.0" + is-installed-globally "~0.4.0" + lazy-ass "^1.6.0" + listr2 "^3.8.3" + lodash "^4.17.21" + log-symbols "^4.0.0" + minimist "^1.2.6" + ospath "^1.2.2" + pretty-bytes "^5.6.0" + proxy-from-env "1.0.0" + request-progress "^3.0.0" + semver "^7.3.2" + supports-color "^8.1.1" + tmp "~0.2.1" + untildify "^4.0.0" + yauzl "^2.10.0" + +dash-ast@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dash-ast/-/dash-ast-1.0.0.tgz#12029ba5fb2f8aa6f0a861795b23c1b4b6c27d37" + integrity sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA== + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== + dependencies: + assert-plus "^1.0.0" + +dayjs@^1.10.4: + version "1.11.5" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.5.tgz#00e8cc627f231f9499c19b38af49f56dc0ac5e93" + integrity sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA== + +debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.0, 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.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +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-properties@^1.1.3, define-properties@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + integrity sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ== + +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== + +deps-sort@^2.0.0, deps-sort@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.1.tgz#9dfdc876d2bcec3386b6829ac52162cda9fa208d" + integrity sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw== + dependencies: + JSONStream "^1.0.3" + shasum-object "^1.0.0" + subarg "^1.0.0" + through2 "^2.0.0" + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +detective@^5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034" + integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw== + dependencies: + acorn-node "^1.8.2" + defined "^1.0.0" + minimist "^1.2.6" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +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" + +domain-browser@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA== + dependencies: + readable-stream "^2.0.2" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +electron-to-chromium@^1.4.251: + version "1.4.256" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.256.tgz#c735032f412505e8e0482f147a8ff10cfca45bf4" + integrity sha512-x+JnqyluoJv8I0U9gVe+Sk2st8vF0CzMt78SXxuoWCooLLY2k5VerIBdpvG7ql6GKI4dzNnPjmqgDJ76EdaAKw== + +elliptic@^6.5.3: + 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" + +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== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enquirer@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5, es-abstract@^1.20.0: + version "1.20.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.2.tgz#8495a07bc56d342a3b8ea3ab01bd986700c2ccb3" + integrity sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.1.2" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.2" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + string.prototype.trimend "^1.0.5" + string.prototype.trimstart "^1.0.5" + unbox-primitive "^1.0.2" + +es-shim-unscopables@^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== + dependencies: + has "^1.0.3" + +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" + +esbuild-android-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be" + integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ== + +esbuild-android-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771" + integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg== + +esbuild-darwin-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25" + integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug== + +esbuild-darwin-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73" + integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw== + +esbuild-freebsd-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d" + integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg== + +esbuild-freebsd-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48" + integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q== + +esbuild-linux-32@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5" + integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw== + +esbuild-linux-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652" + integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg== + +esbuild-linux-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b" + integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig== + +esbuild-linux-arm@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59" + integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw== + +esbuild-linux-mips64le@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34" + integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw== + +esbuild-linux-ppc64le@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e" + integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ== + +esbuild-linux-riscv64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8" + integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg== + +esbuild-linux-s390x@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6" + integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA== + +esbuild-netbsd-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81" + integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w== + +esbuild-openbsd-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b" + integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw== + +esbuild-sunos-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da" + integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw== + +esbuild-windows-32@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31" + integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w== + +esbuild-windows-64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4" + integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ== + +esbuild-windows-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982" + integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg== + +esbuild@^0.14.23: + version "0.14.54" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2" + integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA== + 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" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-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.3.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" + integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== + +eslint-config-standard@^16.0.3: + version "16.0.3" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz#6c8761e544e96c531ff92642eeb87842b8488516" + integrity sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg== + +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== + dependencies: + debug "^3.2.7" + resolve "^1.20.0" + +eslint-loader@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-4.0.2.tgz#386a1e21bcb613b3cf2d252a3b708023ccfb41ec" + integrity sha512-EDpXor6lsjtTzZpLUn7KmXs02+nIjGcgees9BYjNkWra3jVq5vVa8IoCKgzT2M7dNNeoMBtaSG83Bd40N3poLw== + dependencies: + find-cache-dir "^3.3.1" + fs-extra "^8.1.0" + loader-utils "^2.0.0" + object-hash "^2.0.3" + schema-utils "^2.6.5" + +eslint-module-utils@^2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" + integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== + dependencies: + debug "^3.2.7" + +eslint-plugin-cypress@^2.12.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz#9aeee700708ca8c058e00cdafe215199918c2632" + integrity sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA== + dependencies: + globals "^11.12.0" + +eslint-plugin-es@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" + integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== + dependencies: + eslint-utils "^2.0.0" + regexpp "^3.0.0" + +eslint-plugin-import@^2.23.4: + version "2.26.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" + integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== + dependencies: + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.3" + has "^1.0.3" + is-core-module "^2.8.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.values "^1.1.5" + resolve "^1.22.0" + tsconfig-paths "^3.14.1" + +eslint-plugin-node@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" + integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== + 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" + +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@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-5.2.0.tgz#a596acc32981627eb36d9d75f9666ac1a4564971" + integrity sha512-SftLb1pUG01QYq2A/hGAWfDRXqYD82zE7j7TopDOyNdU+7SvvoXREls/+PRTY17vUXzXnZA/zfnyKgRH6x4JJw== + +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.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + 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: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.23.1: + version "8.23.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.23.1.tgz#cfd7b3f7fdd07db8d16b4ac0516a29c8d8dca5dc" + integrity sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg== + dependencies: + "@eslint/eslintrc" "^1.3.2" + "@humanwhocodes/config-array" "^0.10.4" + "@humanwhocodes/gitignore-to-minimatch" "^1.0.2" + "@humanwhocodes/module-importer" "^1.0.1" + ajv "^6.10.0" + 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.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.4.0" + esquery "^1.4.0" + 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.1" + globals "^13.15.0" + globby "^11.1.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-sdsl "^4.1.4" + 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.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + +espree@^9.4.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.0.tgz#cd4bc3d6e9336c433265fc0aa016fc1aaf182f8a" + integrity sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + 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== + +eventemitter2@6.4.7: + version "6.4.7" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" + integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== + +events@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-2.1.0.tgz#2a9a1e18e6106e0e812aa9ebd4a819b3c29c0ba5" + integrity sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg== + +events@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +executable@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" + integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== + dependencies: + pify "^2.2.0" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extract-zip@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + +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== + +fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-safe-stringify@^2.0.7: + 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== + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== + dependencies: + pend "~1.2.0" + +figures@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +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.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== + dependencies: + to-regex-range "^5.0.1" + +find-cache-dir@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +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.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +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" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +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-extra@^9.0.0, fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.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" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +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.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== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functions-have-names@^1.2.2: + 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== + +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" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-assigned-identifiers@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" + integrity sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" + integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-stream@^5.0.0, get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +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== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +getos@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" + integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== + dependencies: + async "^3.2.0" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== + dependencies: + assert-plus "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.0, glob@^7.1.3, glob@^7.1.6, glob@^7.2.0: + 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" + +global-dirs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" + integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== + dependencies: + ini "2.0.0" + +globals@^11.1.0, globals@^11.12.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.15.0: + version "13.17.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4" + integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + 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" + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + +has-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@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +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: + 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-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== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.0, 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== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +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" + +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" + +htmlescape@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" + integrity sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg== + +http-signature@~1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" + integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== + dependencies: + assert-plus "^1.0.0" + jsprim "^2.0.2" + sshpk "^1.14.1" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +ieee754@^1.1.13, ieee754@^1.1.4: + 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: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + 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== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +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, inherits@^2.0.4, inherits@~2.0.1, 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== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA== + +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@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + +inline-source-map@~0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" + integrity sha512-0mVWSSbNDvedDWIN4wxLsdPM4a7cIPcpyMxj3QZ406QRwQ6ePGB1YIHxVPjqpcUGbWQ5C+nHTwGNWAGvt7ggVA== + dependencies: + source-map "~0.5.3" + +insert-module-globals@^7.0.0, insert-module-globals@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.2.1.tgz#d5e33185181a4e1f33b15f7bf100ee91890d5cb3" + integrity sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg== + dependencies: + JSONStream "^1.0.3" + acorn-node "^1.5.2" + combine-source-map "^0.8.0" + concat-stream "^1.6.1" + is-buffer "^1.1.0" + path-is-absolute "^1.0.1" + process "~0.11.0" + through2 "^2.0.0" + undeclared-identifiers "^1.1.2" + xtend "^4.0.0" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +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-buffer@^1.1.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.6" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.6.tgz#fd6170b0b8c7e2cc73de342ef8284a2202023c44" + integrity sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q== + +is-ci@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" + integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== + dependencies: + ci-info "^3.2.0" + +is-core-module@^2.8.1, is-core-module@^2.9.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + +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-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +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-installed-globally@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== + dependencies: + global-dirs "^3.0.0" + is-path-inside "^3.0.2" + +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-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.2, is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +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: + 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== + 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-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.3, is-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.9.tgz#246d77d2871e7d9f5aeb1d54b9f52c71329ece67" + integrity sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + +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-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +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@~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== + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== + +js-sdsl@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.4.tgz#78793c90f80e8430b7d8dc94515b6c77d98a26a6" + integrity sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw== + +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@^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" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +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-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +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== + +json-stable-stringify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" + integrity sha512-nKtD/Qxm7tWdZqJoldEC7fF0S41v0mWbeaXG3637stOWfyGxTgWTYE2wtfKmjzpvxv2MA2xzxsXOIiwUpkX6Qw== + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2, json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + +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" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA== + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + +jsprim@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-2.0.2.tgz#77ca23dbcd4135cd364800d22ff82c2185803d4d" + integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +jwt-decode@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59" + integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A== + +labeled-stream-splicer@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz#42a41a16abcd46fd046306cf4f2c3576fffb1c21" + integrity sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw== + dependencies: + inherits "^2.0.1" + stream-splicer "^2.0.0" + +lazy-ass@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" + integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== + +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" + +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== + +listr2@^3.8.3: + version "3.14.0" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" + integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.1" + through "^2.3.8" + wrap-ansi "^7.0.0" + +loader-utils@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +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.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.memoize@~3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" + integrity sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.once@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +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" + +make-dir@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +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.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.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.19: + 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" + +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== + +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.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.1.0, minimist@^1.2.0, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + +module-deps@^6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-6.2.3.tgz#15490bc02af4b56cf62299c7c17cba32d71a96ee" + integrity sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA== + dependencies: + JSONStream "^1.0.3" + browser-resolve "^2.0.0" + cached-path-relative "^1.0.2" + concat-stream "~1.6.0" + defined "^1.0.0" + detective "^5.2.0" + duplexer2 "^0.1.2" + inherits "^2.0.1" + parents "^1.0.0" + readable-stream "^2.0.2" + resolve "^1.4.0" + stream-combiner2 "^1.1.1" + subarg "^1.0.0" + through2 "^2.0.0" + xtend "^4.0.0" + +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.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== + +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== + +node-hook@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-hook/-/node-hook-1.0.0.tgz#82ca39af991d726d5c7952e59c992378bb296f7e" + integrity sha512-tBTIHwkzXvbesP0fY495VsqSWCOS5Ttt5+mAmeqUC1yglCiSYarNewfi2Q+HOL+M6pZYYqwGU6jIi5+gIHQbpg== + +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== + +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-run-path@^4.0.0: + 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" + +object-assign@^4.1.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-hash@^2.0.3: + version "2.2.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== + +object-inspect@^1.12.2, object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== + +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.0, 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== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.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: + 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.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +os-browserify@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A== + +ospath@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" + integrity sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA== + +outpipe@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/outpipe/-/outpipe-1.1.1.tgz#50cf8616365e87e031e29a5ec9339a3da4725fa2" + integrity sha512-BnNY/RwnDrkmQdUa9U+OfN/Y7AWmKuUPCCd+hbRclZnnANvYpO72zp/a6Q4n829hPbdqEac31XCcsvlEvb+rtA== + dependencies: + shell-quote "^1.4.2" + +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-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +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== + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +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" + +parents@^1.0.0, parents@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" + integrity sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg== + dependencies: + path-platform "~0.11.15" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^5.0.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" + +path-browserify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-browserify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +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, path-is-absolute@^1.0.1: + 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-platform@~0.11.15: + version "0.11.15" + resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" + integrity sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg== + +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== + +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + +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.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pkg-dir@^4.1.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" + +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.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + +pretty-bytes@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== + +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== + +process@~0.11.0: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +proxy-from-env@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== + +psl@^1.1.28: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +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== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== + +punycode@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@~6.5.2: + version "6.5.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== + +querystring-es3@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA== + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== + +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== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +read-only-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" + integrity sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w== + dependencies: + readable-stream "^2.0.2" + +readable-stream@3, readable-stream@^3.5.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@~2.3.6: + 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" + +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" + +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== + +regenerate-unicode-properties@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" + integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537" + integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexp-match-indices@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regexp-match-indices/-/regexp-match-indices-1.0.2.tgz#cf20054a6f7d5b3e116a701a7b00f82889d10da6" + integrity sha512-DwZuAkt8NF5mKwGGER1EGh2PRqyvhRhhLviH+R8y8dIuaQROlUfXjt4s9ZTXstIsSkptf06BSvwcEmmfheJJWQ== + dependencies: + regexp-tree "^0.1.11" + +regexp-tree@^0.1.11: + version "0.1.24" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.24.tgz#3d6fa238450a4d66e5bc9c4c14bb720e2196829d" + integrity sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw== + +regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + +regexpp@^3.0.0, regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.2.1.tgz#a69c26f324c1e962e9ffd0b88b055caba8089139" + integrity sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsgen "^0.7.1" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + +regjsgen@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.7.1.tgz#ee5ef30e18d3f09b7c369b76e7c2373ed25546f6" + integrity sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA== + +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + +request-progress@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" + integrity sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg== + dependencies: + throttleit "^1.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@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-2.0.0.tgz#ac06991418a7623edc119084edc98b0e6bf05a41" + integrity sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ== + dependencies: + resolve-from "^5.0.0" + +resolve@^1.1.4, resolve@^1.10.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.4.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.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" + +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.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +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" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +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@^7.5.1: + version "7.5.6" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc" + integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== + dependencies: + tslib "^2.1.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, 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-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== + +safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^2.6.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.2, semver@^7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: + 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" + +shasum-object@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shasum-object/-/shasum-object-1.0.0.tgz#0b7b74ff5b66ecf9035475522fa05090ac47e29e" + integrity sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg== + dependencies: + fast-safe-stringify "^2.0.7" + +shasum@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" + integrity sha512-UTzHm/+AzKfO9RgPgRpDIuMSNie1ubXRaljjlhFMNGYoG7z+rm9AHLPMf70R7887xboDH9Q+5YQbWKObFHEAtw== + dependencies: + json-stable-stringify "~0.0.0" + sha.js "~2.4.4" + +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== + +shell-quote@^1.4.2, shell-quote@^1.6.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" + integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== + +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== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2: + 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== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +source-map@~0.5.3: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +sshpk@^1.14.1: + version "1.17.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stream-browserify@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-browserify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +stream-combiner2@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" + integrity sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw== + dependencies: + duplexer2 "~0.1.0" + readable-stream "^2.0.2" + +stream-http@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5" + integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.4" + readable-stream "^3.6.0" + xtend "^4.0.2" + +stream-splicer@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.1.tgz#0b13b7ee2b5ac7e0609a7463d83899589a363fcd" + integrity sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg== + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.2" + +string-width@^4.1.0, 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.prototype.trimend@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz#914a65baaab25fbdd4ee291ca7dde57e869cb8d0" + integrity sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +string.prototype.trimstart@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz#5466d93ba58cfa2134839f81d7f42437e8c01fef" + integrity sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.19.5" + +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@^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-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.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + integrity sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg== + dependencies: + minimist "^1.1.0" + +supports-color@^5.3.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.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.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +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== + +syntax-error@^1.1.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.4.0.tgz#2d9d4ff5c064acb711594a3e3b95054ad51d907c" + integrity sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w== + dependencies: + acorn-node "^1.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 sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +throttleit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + integrity sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g== + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through2@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== + dependencies: + readable-stream "3" + +"through@>=2.2.7 <3", through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + integrity sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q== + dependencies: + process "~0.11.0" + +tmp@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +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" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tsconfig-paths@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + 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.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + +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" + +tty-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== + +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" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + +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== + +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== + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== + +typescript@^4.7.4: + version "4.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.3.tgz#d59344522c4bc464a65a730ac695007fdb66dd88" + integrity sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig== + +umd@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.3.tgz#aa9fe653c42b9097678489c01000acb69f0b26cf" + integrity sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow== + +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" + +undeclared-identifiers@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz#9254c1d37bdac0ac2b52de4b6722792d2a91e30f" + integrity sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw== + dependencies: + acorn-node "^1.3.0" + dash-ast "^1.0.0" + get-assigned-identifiers "^1.2.0" + simple-concat "^1.0.0" + xtend "^4.0.1" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +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.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +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== + +update-browserslist-db@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz#2924d3927367a38d5c555413a7ce138fc95fcb18" + integrity sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +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@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ== + dependencies: + punycode "1.3.2" + querystring "0.2.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@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ== + dependencies: + inherits "2.0.1" + +util@~0.10.1: + version "0.10.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" + integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A== + dependencies: + inherits "2.0.3" + +util@~0.12.0: + version "0.12.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" + integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + safe-buffer "^5.1.2" + which-typed-array "^1.1.2" + +uuid@8.3.2, 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== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +watchify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/watchify/-/watchify-4.0.0.tgz#53b002d51e7b0eb640b851bb4de517a689973392" + integrity sha512-2Z04dxwoOeNxa11qzWumBTgSAohTC0+ScuY7XMenPnH+W2lhTcpEOJP4g2EIG/SWeLadPk47x++Yh+8BqPM/lA== + dependencies: + anymatch "^3.1.0" + browserify "^17.0.0" + chokidar "^3.4.0" + defined "^1.0.0" + outpipe "^1.1.0" + through2 "^4.0.2" + xtend "^4.0.2" + +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.2: + version "1.1.8" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.8.tgz#0cfd53401a6f334d90ed1125754a42ed663eb01f" + integrity sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.20.0" + for-each "^0.3.3" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.9" + +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.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== + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + 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" + +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== + +xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +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== + +yaml@^1.10.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + +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/e2e-tests/playwright/Dockerfile b/e2e-tests/playwright/Dockerfile new file mode 100644 index 000000000..c0dfbde47 --- /dev/null +++ b/e2e-tests/playwright/Dockerfile @@ -0,0 +1,42 @@ +############################################################################### +# Dockerfile to create a ready-to-use Playwright Docker image for end-to-end +# testing. +# +# To avoid hardcoded versoning of Playwright, this Dockerfile is a custom +# version of the ready-to-use Dockerfile privided by Playwright developement +# (https://github.com/microsoft/playwright/blob/main/utils/docker/Dockerfile.focal) +# +# Here the latest stable versions of the browsers Chromium, Firefox, and Webkit +# (Safari) are installed, icluding all dependencies based on Ubuntu specified by +# Playwright developement. +############################################################################### + +FROM ubuntu:focal + +# set a timezone for the Playwright browser dependency installation +ARG TZ=Europe/Berlin + +ARG DOCKER_WORKDIR=/tests/ +WORKDIR $DOCKER_WORKDIR + +# package manager preparation +RUN apt-get -qq update && apt-get install -qq -y curl gpg > /dev/null +# for Node.js +RUN curl -sL https://deb.nodesource.com/setup_16.x | bash - +# for Yarn +RUN curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ + echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list + +# install node v16 and Yarn +RUN apt-get -qq update && apt-get install -qq -y nodejs yarn + +COPY tests/package.json tests/yarn.lock $DOCKER_WORKDIR + +# install Playwright with all dependencies +# for the browsers chromium, firefox, and webkit +RUN yarn install && yarn playwright install --with-deps + +# clean up +RUN rm -rf /var/lib/apt/lists/* && apt-get -qq clean + +COPY tests/ $DOCKER_WORKDIR diff --git a/e2e-tests/playwright/README.md b/e2e-tests/playwright/README.md new file mode 100644 index 000000000..a3a2b34bb --- /dev/null +++ b/e2e-tests/playwright/README.md @@ -0,0 +1,24 @@ +# Gradido End-to-End Testing with [Playwright](https://playwright.dev/) (CI-ready via Docker) + + +A sample setup to show-case Playwright (using Typescript) as an end-to-end testing tool for Gradido runniing in a Docker container. +Here we have a simple UI-based happy path login test running against the DEV system. + +## Precondition +Since dependencies and configurations for Github Actions integration is not set up yet, please run in root directory + +```bash +docker-compose up +``` + +to boot up the DEV system, before running the test. + +## Execute the test + +```bash +# build a Docker image from the Dockerfile +docker build -t gradido_e2e-tests-playwright . + +# run the Docker container and execute the given tests +docker run -it --network=host gradido_e2e-tests-playwright yarn playwright-e2e-tests +``` diff --git a/e2e-tests/playwright/tests/global-setup.ts b/e2e-tests/playwright/tests/global-setup.ts new file mode 100644 index 000000000..6f9dad9c4 --- /dev/null +++ b/e2e-tests/playwright/tests/global-setup.ts @@ -0,0 +1,8 @@ +import { FullConfig } from '@playwright/test'; + +async function globalSetup(config: FullConfig) { + process.env.EMAIL = 'bibi@bloxberg.de'; + process.env.PASSWORD = 'Aa12345_'; +} + +export default globalSetup; diff --git a/e2e-tests/playwright/tests/gradido_login.spec.ts b/e2e-tests/playwright/tests/gradido_login.spec.ts new file mode 100644 index 000000000..0853780d1 --- /dev/null +++ b/e2e-tests/playwright/tests/gradido_login.spec.ts @@ -0,0 +1,15 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from './models/login_page'; +import { WelcomePage } from './models/welcome_page'; + + +test('Gradido login test (happy path)', async ({ page }) => { + const { EMAIL, PASSWORD } = process.env; + const loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.enterEmail(EMAIL); + await loginPage.enterPassword(PASSWORD); + await loginPage.submitLogin(); + // assertions + await expect(page).toHaveURL('./overview'); +}); diff --git a/e2e-tests/playwright/tests/models/login_page.ts b/e2e-tests/playwright/tests/models/login_page.ts new file mode 100644 index 000000000..50abb4933 --- /dev/null +++ b/e2e-tests/playwright/tests/models/login_page.ts @@ -0,0 +1,33 @@ +import { expect, test, Locator, Page } from '@playwright/test'; + +export class LoginPage { + readonly page: Page; + readonly url: string; + readonly emailInput: Locator; + readonly passwordInput: Locator; + readonly submitBtn: Locator; + + constructor(page: Page) { + this.page = page; + this.url = './login'; + this.emailInput = page.locator('id=Email-input-field'); + this.passwordInput = page.locator('id=Password-input-field'); + this.submitBtn = page.locator('text=Login'); + } + + async goto() { + await this.page.goto(this.url); + } + + async enterEmail(email: string) { + await this.emailInput.fill(email); + } + + async enterPassword(password: string) { + await this.passwordInput.fill(password); + } + + async submitLogin() { + await this.submitBtn.click(); + } +} diff --git a/e2e-tests/playwright/tests/models/welcome_page.ts b/e2e-tests/playwright/tests/models/welcome_page.ts new file mode 100644 index 000000000..81d73a771 --- /dev/null +++ b/e2e-tests/playwright/tests/models/welcome_page.ts @@ -0,0 +1,13 @@ +import { expect, Locator, Page } from '@playwright/test'; + +export class WelcomePage { + readonly page: Page; + readonly url: string; + readonly profileLink: Locator; + + constructor(page: Page){ + this.page = page; + this.url = './overview'; + this.profileLink = page.locator('href=/profile'); + } +} diff --git a/e2e-tests/playwright/tests/playwright.config.ts b/e2e-tests/playwright/tests/playwright.config.ts new file mode 100644 index 000000000..84b010dc5 --- /dev/null +++ b/e2e-tests/playwright/tests/playwright.config.ts @@ -0,0 +1,21 @@ +import type { PlaywrightTestConfig } from '@playwright/test'; + +const config: PlaywrightTestConfig = { + globalSetup: require.resolve('./global-setup'), + ignoreHTTPSErrors: true, + locale: 'de-DE', + reporter: process.env.CI ? 'github' : 'list', + retries: 1, + screenshot: 'only-on-failure', + testDir: '.', + timeout: 30000, + trace: 'on-first-retry', + video: 'never', + viewport: { width: 1280, height: 720 }, + use: { + baseURL: process.env.URL || 'http://localhost:3000', + browserName: 'webkit', + + }, +}; +export default config; diff --git a/frontend/.env.dist b/frontend/.env.dist index 65d9ae305..4127f339a 100644 --- a/frontend/.env.dist +++ b/frontend/.env.dist @@ -1,4 +1,4 @@ -CONFIG_VERSION=v2.2022-04-07 +CONFIG_VERSION=v3.2022-09-16 # Environment DEFAULT_PUBLISHER_ID=2896 @@ -21,4 +21,7 @@ META_DESCRIPTION_DE="Dankbarkeit ist die Währung der neuen Zeit. Immer mehr Men META_DESCRIPTION_EN="Gratitude is the currency of the new age. More and more people are unleashing their potential and shaping a good future for all." META_KEYWORDS_DE="Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natürliche Ökonomie des Lebens, Ökonomie, Ökologie, Potenzialentfaltung, Schenken und Danken, Kreislauf des Lebens, Geldsystem" META_KEYWORDS_EN="Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System" -META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" \ No newline at end of file +META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" + +# Support Mail +SUPPORT_MAIL=support@supportmail.com \ No newline at end of file diff --git a/frontend/.env.template b/frontend/.env.template index 6d6b83fc7..0b9d34b38 100644 --- a/frontend/.env.template +++ b/frontend/.env.template @@ -21,4 +21,7 @@ META_DESCRIPTION_DE=$META_DESCRIPTION_DE META_DESCRIPTION_EN=$META_DESCRIPTION_EN META_KEYWORDS_DE=$META_KEYWORDS_DE META_KEYWORDS_EN=$META_KEYWORDS_EN -META_AUTHOR=$META_AUTHOR \ No newline at end of file +META_AUTHOR=$META_AUTHOR + +# Support Mail +SUPPORT_MAIL=$SUPPORT_MAIL \ No newline at end of file diff --git a/frontend/src/components/Inputs/InputPasswordConfirmation.vue b/frontend/src/components/Inputs/InputPasswordConfirmation.vue index 8154984ef..3209018c3 100644 --- a/frontend/src/components/Inputs/InputPasswordConfirmation.vue +++ b/frontend/src/components/Inputs/InputPasswordConfirmation.vue @@ -12,6 +12,7 @@ atLeastOneSpecialCharater: true, noWhitespaceCharacters: true, }" + id="new-password-input-field" :label="register ? $t('form.password') : $t('form.password_new')" :showAllErrors="true" :immediate="true" diff --git a/frontend/src/components/LinkInformations/RedeemValid.vue b/frontend/src/components/LinkInformations/RedeemValid.vue index 353fefaf8..c468a396a 100644 --- a/frontend/src/components/LinkInformations/RedeemValid.vue +++ b/frontend/src/components/LinkInformations/RedeemValid.vue @@ -3,7 +3,7 @@
- + {{ $t('gdd_per_link.redeem') }}
diff --git a/frontend/src/components/Menu/Navbar.vue b/frontend/src/components/Menu/Navbar.vue index d1fe3af9d..8727dbd2f 100644 --- a/frontend/src/components/Menu/Navbar.vue +++ b/frontend/src/components/Menu/Navbar.vue @@ -14,7 +14,12 @@
{{ pending ? $t('em-dash') : balance | amount }} {{ $t('GDD') }}
- + {{ $store.state.firstName }} {{ $store.state.lastName }} {{ $store.state.email }} diff --git a/frontend/src/components/Menu/Sidebar.vue b/frontend/src/components/Menu/Sidebar.vue index 4b38851b2..f6abb6fbc 100644 --- a/frontend/src/components/Menu/Sidebar.vue +++ b/frontend/src/components/Menu/Sidebar.vue @@ -24,7 +24,7 @@ {{ $t('navigation.community') }} - + {{ $t('navigation.profile') }} @@ -48,7 +48,7 @@ {{ $t('navigation.admin_area') }} - + {{ $t('navigation.logout') }} diff --git a/frontend/src/components/UserSettings/UserPassword.vue b/frontend/src/components/UserSettings/UserPassword.vue index 0ba1576e8..2f571d400 100644 --- a/frontend/src/components/UserSettings/UserPassword.vue +++ b/frontend/src/components/UserSettings/UserPassword.vue @@ -6,6 +6,7 @@ {{ $t('settings.password.change-password') }} @@ -36,6 +37,7 @@ :variant="disabled ? 'light' : 'success'" class="mt-4" :disabled="disabled" + data-test="submit-new-password-btn" > {{ $t('form.save') }} diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index 917a25d70..5ab5f2392 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -8,7 +8,7 @@ const constants = { DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v2.2022-04-07', + EXPECTED: 'v3.2022-09-16', CURRENT: '', }, } @@ -60,6 +60,10 @@ const meta = { META_AUTHOR: process.env.META_AUTHOR || 'Bernd Hückstädt - Gradido-Akademie', } +const supportmail = { + SUPPORT_MAIL: process.env.SUPPORT_MAIL || 'support@supportmail.com', +} + // Check config version constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT if ( @@ -79,6 +83,7 @@ const CONFIG = { ...endpoints, ...community, ...meta, + ...supportmail, } module.exports = CONFIG diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index e6b12b0fa..1ed8af19f 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -178,7 +178,6 @@ "no-redeem": "Du darfst deinen eigenen Link nicht einlösen!", "not-copied": "Dein Gerät lässt das Kopieren leider nicht zu! Bitte kopiere den Link von Hand!", "redeem": "Einlösen", - "redeem-text": "Willst du den Betrag jetzt einlösen?", "redeemed": "Erfolgreich eingelöst! Deinem Konto wurden {n} GDD gutgeschrieben.", "redeemed-at": "Der Link wurde bereits am {date} eingelöst.", "redeemed-title": "eingelöst", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 07125eceb..113fa1cb9 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -178,7 +178,6 @@ "no-redeem": "You not allowed to redeem your own link!", "not-copied": "Unfortunately, your device does not allow copying! Please copy the link by hand!", "redeem": "Redeem", - "redeem-text": "Do you want to redeem the amount now?", "redeemed": "Successfully redeemed! Your account has been credited with {n} GDD.", "redeemed-at": "The link was already redeemed on {date}.", "redeemed-title": "redeemed", diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index 987bb71ef..b2a229f1c 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -180,7 +180,6 @@ "no-redeem": "No puedes canjear tu propio enlace!", "not-copied": "¡Desafortunadamente, su dispositivo no permite copiar! Copie el enlace manualmente!", "redeem": "Canjear", - "redeem-text": "¿Quieres canjear el importe ahora?", "redeemed": "¡Canjeado con éxito! Tu cuenta ha sido acreditada con {n} GDD.", "redeemed-at": "El enlace ya se canjeó el {date}.", "redeemed-title": "canjeado", diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index 61037af1a..e7ac18a18 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -180,7 +180,6 @@ "no-redeem": "Vous n´êtes pas autorisé à percevoir votre propre lien!", "not-copied": "Malheureusement votre appareil ne permet pas de copier! Veuillez copier le lien manuellement svp!", "redeem": "Encaisser", - "redeem-text": "Voulez-vous percevoir le montant maintenant?", "redeemed": "Encaissé avec succès! Votre compte est crédité de {n} GDD.", "redeemed-at": "Le lien a déjà été perçu le {date}.", "redeemed-title": "encaisser", diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json index 99b972514..34f484fd7 100644 --- a/frontend/src/locales/nl.json +++ b/frontend/src/locales/nl.json @@ -180,7 +180,6 @@ "no-redeem": "Je mag je eigen link niet inwisselen!", "not-copied": "Jouw apparaat laat het kopiëren helaas niet toe! Kopieer de link alsjeblieft met de hand!", "redeem": "Inwisselen", - "redeem-text": "Wil je het bedrag nu inwisselen?", "redeemed": "Succesvol ingewisseld! Op jouw rekening werden {n} GDD bijgeschreven.", "redeemed-at": "De link werd al op {date} ingewisseld.", "redeemed-title": "ingewisseld", diff --git a/frontend/src/pages/InfoStatistic.vue b/frontend/src/pages/InfoStatistic.vue index 309404f48..1e09f83ed 100644 --- a/frontend/src/pages/InfoStatistic.vue +++ b/frontend/src/pages/InfoStatistic.vue @@ -83,7 +83,7 @@ export default { countAdminUser: null, itemsContributionLinks: [], itemsAdminUser: [], - supportMail: 'support@supportemail.de', + supportMail: CONFIG.SUPPORT_MAIL, membersCount: '1203', totalUsers: null, totalGradidoCreated: null, diff --git a/frontend/src/pages/TransactionLink.spec.js b/frontend/src/pages/TransactionLink.spec.js index b1bbd8950..d5a75aa4a 100644 --- a/frontend/src/pages/TransactionLink.spec.js +++ b/frontend/src/pages/TransactionLink.spec.js @@ -282,19 +282,11 @@ describe('TransactionLink', () => { }) describe('redeem link with success', () => { - let spy - beforeEach(async () => { - spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') apolloMutateMock.mockResolvedValue() - spy.mockImplementation(() => Promise.resolve(true)) await wrapper.findComponent({ name: 'RedeemValid' }).find('button').trigger('click') }) - it('opens the modal', () => { - expect(spy).toBeCalledWith('gdd_per_link.redeem-text') - }) - it('calls the API', () => { expect(apolloMutateMock).toBeCalledWith( expect.objectContaining({ @@ -316,37 +308,9 @@ describe('TransactionLink', () => { }) }) - describe('cancel redeem link', () => { - let spy - - beforeEach(async () => { - spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') - apolloMutateMock.mockResolvedValue() - spy.mockImplementation(() => Promise.resolve(false)) - await wrapper.findComponent({ name: 'RedeemValid' }).find('button').trigger('click') - }) - - it('does not call the API', () => { - expect(apolloMutateMock).not.toBeCalled() - }) - - it('does not toasts a success message', () => { - expect(mocks.$t).not.toBeCalledWith('gdd_per_link.redeemed', { n: '22' }) - expect(toastSuccessSpy).not.toBeCalled() - }) - - it('does not push the route', () => { - expect(routerPushMock).not.toBeCalled() - }) - }) - describe('redeem link with error', () => { - let spy - beforeEach(async () => { - spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm') apolloMutateMock.mockRejectedValue({ message: 'Oh Noo!' }) - spy.mockImplementation(() => Promise.resolve(true)) await wrapper.findComponent({ name: 'RedeemValid' }).find('button').trigger('click') }) diff --git a/frontend/src/pages/TransactionLink.vue b/frontend/src/pages/TransactionLink.vue index 57236b55c..bd1909d7d 100644 --- a/frontend/src/pages/TransactionLink.vue +++ b/frontend/src/pages/TransactionLink.vue @@ -14,7 +14,7 @@ @@ -98,11 +98,6 @@ export default { this.$router.push('/overview') }) }, - redeemLink(amount) { - this.$bvModal.msgBoxConfirm(this.$t('gdd_per_link.redeem-text')).then((value) => { - if (value) this.mutationLink(amount) - }) - }, }, computed: { isContributionLink() { diff --git a/frontend/src/plugins/apolloProvider.js b/frontend/src/plugins/apolloProvider.js index 4a0ff9914..05954d36b 100644 --- a/frontend/src/plugins/apolloProvider.js +++ b/frontend/src/plugins/apolloProvider.js @@ -12,6 +12,7 @@ const authLink = new ApolloLink((operation, forward) => { operation.setContext({ headers: { Authorization: token && token.length > 0 ? `Bearer ${token}` : '', + clientRequestTime: new Date().toString(), }, }) return forward(operation).map((response) => { diff --git a/frontend/src/plugins/apolloProvider.test.js b/frontend/src/plugins/apolloProvider.test.js index aeb02243c..31e1a664b 100644 --- a/frontend/src/plugins/apolloProvider.test.js +++ b/frontend/src/plugins/apolloProvider.test.js @@ -98,6 +98,7 @@ describe('apolloProvider', () => { expect(setContextMock).toBeCalledWith({ headers: { Authorization: 'Bearer some-token', + clientRequestTime: expect.any(String), }, }) }) @@ -113,6 +114,7 @@ describe('apolloProvider', () => { expect(setContextMock).toBeCalledWith({ headers: { Authorization: '', + clientRequestTime: expect.any(String), }, }) }) diff --git a/package.json b/package.json index 8bc24d402..d0b45a8c7 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "release": "scripts/release.sh" }, "dependencies": { - "auto-changelog": "^2.4.0" + "auto-changelog": "^2.4.0", + "uuid": "^8.3.2" } } diff --git a/yarn.lock b/yarn.lock index d9c16e6f7..2c8f9b681 100644 --- a/yarn.lock +++ b/yarn.lock @@ -81,6 +81,11 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.1.tgz#2749d4b8b5b7d67460b4a418023ff73c3fefa60a" integrity sha512-EWhx3fHy3M9JbaeTnO+rEqzCe1wtyQClv6q3YWq0voOj4E+bMZBErVS1GAHPDiRGONYq34M1/d8KuQMgvi6Gjw== +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== + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"