From eda971a09cf3d7ebb7b924c88dc20aa01655b91c Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 20 Sep 2021 13:57:02 +0200 Subject: [PATCH 01/37] add release plan image --- docu/graphics/AnachBüberweisen.drawio | 103 ++++++++++++++++++++++++++ docu/graphics/AnachBüberweisen.png | Bin 0 -> 101882 bytes 2 files changed, 103 insertions(+) create mode 100644 docu/graphics/AnachBüberweisen.drawio create mode 100644 docu/graphics/AnachBüberweisen.png diff --git a/docu/graphics/AnachBüberweisen.drawio b/docu/graphics/AnachBüberweisen.drawio new file mode 100644 index 000000000..e27e275f5 --- /dev/null +++ b/docu/graphics/AnachBüberweisen.drawio @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docu/graphics/AnachBüberweisen.png b/docu/graphics/AnachBüberweisen.png new file mode 100644 index 0000000000000000000000000000000000000000..5fec2a577398635ff70e73fa41e2074aa3d8a9d3 GIT binary patch literal 101882 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
6pqTHH;_RT*9qBy`6CU5W> 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 literal 0 HcmV?d00001 From 1b3ff38ed7c8dc0b8f427afb63f03c80a02ef1e8 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 23 Sep 2021 18:08:30 +0200 Subject: [PATCH 02/37] update password check, allow every special char (everything what isn't a-z, A-Z or 0-9) --- login_server/src/LOCALE/de_DE.mo | Bin 2428 -> 2378 bytes login_server/src/LOCALE/de_DE.po | 13 ++++++------- .../cpp/SingletonManager/SessionManager.cpp | 8 ++++---- login_server/src/cpsp/UserUpdatePassword.cpsp | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/login_server/src/LOCALE/de_DE.mo b/login_server/src/LOCALE/de_DE.mo index bfee8efd3031828aef1a46b92818abdfce8812ef..6a1735b6aeff6403fe194c5790665ba6c8fec182 100644 GIT binary patch delta 340 zcmXZWu}T9$6ouh4uIpygC~L9_LNF37R8~oXgls7`A(gd=T3h%85^StQ#R)>%v^J3~ zdhf9o$+}J*wnk)QQ3iB?wlYNAEq^4Jl!qh^LuBg#9u5r6j(NGZ)L}PQ5(9{QrHaBUEZd+qSt#wD& zrY0L|ZHzvG)X@J#gB>{h-g6G`d!Fa~cmCq46G_@jNL75tEi_3f#BFTi83uTR>-dUg zETp8GkrvS5ygw>U;{mqt6pMI^1?=H2_Hh!+X>~M3(MmH2cd&vdID_YC2j61`AOGy( zHRmU6;1Q25cF}%(hjn~IAHQ$~J%-ufZ6vqSiY`sbu@T1EiXKd@Sh5w%CeQv>(nS1e zKFpXqw^^??nj5q8{-GE56Q0QpU3t+U+0HKei-8-2YvF2qoO&6_4Yx!~nZf@K->Lin Dswpwz diff --git a/login_server/src/LOCALE/de_DE.po b/login_server/src/LOCALE/de_DE.po index b4bca3098..2b97bd88c 100644 --- a/login_server/src/LOCALE/de_DE.po +++ b/login_server/src/LOCALE/de_DE.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-06-21 13:37+0200\n" -"PO-Revision-Date: 2021-06-21 13:38+0200\n" +"POT-Creation-Date: 2021-09-23 17:56+0200\n" +"PO-Revision-Date: 2021-09-23 17:59+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: de_DE\n" @@ -455,11 +455,10 @@ msgstr "Gradido: Passwort zurücksetzen" #: src/cpp/SingletonManager/SessionManager.cpp:604 msgid "" "Please enter a valid password with at least 8 characters, upper and lower " -"case letters, at least one number and one special character (@$!%*?&+-_)!" +"case letters, at least one number and one special character!" msgstr "" "Bitte gebe ein gültiges Password ein mit mindestens 8 Zeichen, Groß- und " -"Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen (@$!%*?&+-_) " -"ein!" +"Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen ein!" #: src/cpp/SingletonManager/SessionManager.cpp:610 msgid "Your password is to short!" @@ -478,8 +477,8 @@ msgid "Your password does not contain any number!" msgstr "Dein Passwort enthält keine Zahlen!" #: src/cpp/SingletonManager/SessionManager.cpp:630 -msgid "Your password does not contain special characters (@$!%*?&+-)!" -msgstr "Dein Passwort enthält keine Sonderzeichen (@$!%*?&+-)!" +msgid "Your password does not contain special characters!" +msgstr "Dein Passwort enthält keine Sonderzeichen!" #~ msgid "Account" #~ msgstr "Konto" diff --git a/login_server/src/cpp/SingletonManager/SessionManager.cpp b/login_server/src/cpp/SingletonManager/SessionManager.cpp index d854c2a97..13f2a7dd4 100644 --- a/login_server/src/cpp/SingletonManager/SessionManager.cpp +++ b/login_server/src/cpp/SingletonManager/SessionManager.cpp @@ -46,7 +46,7 @@ bool SessionManager::init() case VALIDATE_NAME: mValidations[i] = new Poco::RegularExpression("^[^<>&;]{2,}$"); break; case VALIDATE_USERNAME: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z][a-zA-Z0-9_-]*$"); break; case VALIDATE_EMAIL: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z0-9.!#$%&?*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"); break; - case VALIDATE_PASSWORD: mValidations[i] = new Poco::RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[@$!%*?&+-_])[A-Za-z0-9@$!%*?&+-_]{8,}$"); break; + case VALIDATE_PASSWORD: mValidations[i] = new Poco::RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9]).{8,}$"); break; case VALIDATE_PASSPHRASE: mValidations[i] = new Poco::RegularExpression("^(?:[a-z]* ){23}[a-z]*\s*$"); break; case VALIDATE_GROUP_ALIAS: mValidations[i] = new Poco::RegularExpression("^[a-z0-9-]{3,120}"); break; case VALIDATE_HEDERA_ID: mValidations[i] = new Poco::RegularExpression("^[0-9]*\.[0-9]*\.[0-9]\.$"); break; @@ -56,7 +56,7 @@ bool SessionManager::init() case VALIDATE_ONLY_HEX: mValidations[i] = new Poco::RegularExpression("^(0x)?[a-fA-F0-9]*$"); break; //case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}$"); break; case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\/?"); break; - case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression(".*[@$!%*?&+-].*"); break; + case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression(".*[^a-zA-Z0-9].*"); break; case VALIDATE_HAS_UPPERCASE_LETTER: mValidations[i] = new Poco::RegularExpression(".*[A-Z].*"); ServerConfig::g_ServerKeySeed->put(i, DRRandom::r64()); @@ -601,7 +601,7 @@ bool SessionManager::checkPwdValidation(const std::string& pwd, NotificationList if (!isValid(pwd, VALIDATE_PASSWORD)) { errorReciver->addError(new Error( lang->gettext("Password"), - lang->gettext("Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character (@$!%*?&+-_)!"))); + lang->gettext("Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character!"))); // @$!%*?&+- if (pwd.size() < 8) { @@ -627,7 +627,7 @@ bool SessionManager::checkPwdValidation(const std::string& pwd, NotificationList else if (!isValid(pwd, VALIDATE_HAS_SPECIAL_CHARACTER)) { errorReciver->addError(new Error( lang->gettext("Password"), - lang->gettext("Your password does not contain special characters (@$!%*?&+-)!"))); + lang->gettext("Your password does not contain special characters!"))); } return false; diff --git a/login_server/src/cpsp/UserUpdatePassword.cpsp b/login_server/src/cpsp/UserUpdatePassword.cpsp index 04d1e487e..260a29475 100644 --- a/login_server/src/cpsp/UserUpdatePassword.cpsp +++ b/login_server/src/cpsp/UserUpdatePassword.cpsp @@ -85,7 +85,7 @@ enum PageState {

Bitte denke dir ein sicheres Passwort aus, das mindestens 8 Zeichen lang ist, einen Klein- und einen Großbuchstaben enthält, - eine Zahl und eines der folgenden Sonderzeichen: @$!%*?&+- + eine Zahl und ein Sonderzeichen.

From 6653dd4be811a997bafe9181fcd0526c5ff2ca88 Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Fri, 24 Sep 2021 10:59:17 +0200 Subject: [PATCH 03/37] listTransactions in apollo ; --- .../src/graphql/inputs/TransactionInput.ts | 2 +- backend/src/graphql/models/Transaction.ts | 3 + .../graphql/resolvers/TransactionResolver.ts | 32 ++++++++-- .../src/graphql/resolvers/listTransactions.ts | 61 +++++++++++++++++++ backend/src/typeorm/entity/User.ts | 3 +- backend/src/typeorm/entity/UserTransaction.ts | 35 +++++++++++ 6 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 backend/src/graphql/resolvers/listTransactions.ts create mode 100644 backend/src/typeorm/entity/UserTransaction.ts diff --git a/backend/src/graphql/inputs/TransactionInput.ts b/backend/src/graphql/inputs/TransactionInput.ts index a62d86a65..1f79d193e 100644 --- a/backend/src/graphql/inputs/TransactionInput.ts +++ b/backend/src/graphql/inputs/TransactionInput.ts @@ -9,7 +9,7 @@ export class TransactionListInput { items: number @Field(() => String) - order: string + order: "ASC" | "DESC" } @ArgsType() diff --git a/backend/src/graphql/models/Transaction.ts b/backend/src/graphql/models/Transaction.ts index 87535c4a2..a2f2d19c1 100644 --- a/backend/src/graphql/models/Transaction.ts +++ b/backend/src/graphql/models/Transaction.ts @@ -30,6 +30,9 @@ export class Transaction { @Field(() => Number) balance: number + @Field(() => Number) + totalBalance: number + @Field({ nullable: true }) decayStart?: number diff --git a/backend/src/graphql/resolvers/TransactionResolver.ts b/backend/src/graphql/resolvers/TransactionResolver.ts index d18c7c300..cd17ae993 100644 --- a/backend/src/graphql/resolvers/TransactionResolver.ts +++ b/backend/src/graphql/resolvers/TransactionResolver.ts @@ -6,6 +6,11 @@ import CONFIG from '../../config' import { TransactionList } from '../models/Transaction' import { TransactionListInput, TransactionSendArgs } from '../inputs/TransactionInput' import { apiGet, apiPost } from '../../apis/HttpRequest' +import { User } from '../../typeorm/entity/User' +import { Balance } from '../../typeorm/entity/Balance' +import listTransactions from './listTransactions' +import { roundFloorFrom4 } from '../../util/round' +import calculateDecay from '../../util/decay' @Resolver() export class TransactionResolver { @@ -15,11 +20,30 @@ export class TransactionResolver { @Args() { firstPage = 1, items = 25, order = 'DESC' }: TransactionListInput, @Ctx() context: any, ): Promise { - const result = await apiGet( - `${CONFIG.COMMUNITY_API_URL}listTransactions/${firstPage}/${items}/${order}/${context.sessionId}`, - ) + // get public key for current logged in user + const result = await apiGet(CONFIG.LOGIN_API_URL + 'login?session_id=' + context.sessionId) if (!result.success) throw new Error(result.data) - return new TransactionList(result.data) + + // load user + const userEntity = await User.findByPubkeyHex(result.data.user.public_hex) + + const transactions = await listTransactions(firstPage, items, order, userEntity) + + // get gdt sum + const resultGDTSum = await apiPost( + `${CONFIG.GDT_API_URL}/GdtEntries/sumPerEmailApi`, {email: userEntity.email} + ) + if (!resultGDTSum.success) throw new Error(resultGDTSum.data) + transactions.gdtSum = resultGDTSum.data.sum + + // get balance + const balanceEntity = await Balance.findByUser(userEntity.id) + const now = new Date() + transactions.balance = roundFloorFrom4(balanceEntity.amount) + transactions.decay = roundFloorFrom4(calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now)) + transactions.decayDate = now.toString() + + return transactions } @Authorized() diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts new file mode 100644 index 000000000..a7889a954 --- /dev/null +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -0,0 +1,61 @@ + +import { User } from '../../typeorm/entity/User' +import { TransactionList, Transaction } from '../models/Transaction' +import { UserTransaction } from '../../typeorm/entity/UserTransaction' + +function calculateAndAddDecayTransactions( + userTransactions:UserTransaction[], + user: User, + decay:boolean, + skipFirstTransaction:boolean +): Transaction[] +{ + let transactions: Transaction[] = [] + + return transactions +} + + +export default async function listTransactions( + firstPage:number, + items:number, + order:"ASC" | "DESC", + user:User) : Promise +{ + + let limit = items + let offset = 0 + let skipFirstTransaction = false + if(firstPage > 1) { + offset = (( firstPage - 1 ) * items) - 1; + limit++; + } + + if(offset && order == 'ASC') { + offset--; + } + let [userTransactions, userTransactionsCount] = await UserTransaction.findByUserPaged(user.id, limit, offset, order) + skipFirstTransaction = userTransactionsCount > offset + limit + const decay = !(firstPage > 1) + let transactions: Transaction[] = [] + if(userTransactions.length) { + if(order === 'DESC') { + userTransactions = userTransactions.reverse() + } + let transactions = calculateAndAddDecayTransactions(userTransactions, user, decay, skipFirstTransaction) + if(order === 'DESC') { + transactions = transactions.reverse() + } + } + + const transactionList = new TransactionList({ + gdtSum: 0, + count: userTransactionsCount, + balance: 0, + decay: 0, + decay_date: '', + transactions: transactions + }) + + return transactionList +} \ No newline at end of file diff --git a/backend/src/typeorm/entity/User.ts b/backend/src/typeorm/entity/User.ts index cb9de27c8..c675a1d53 100644 --- a/backend/src/typeorm/entity/User.ts +++ b/backend/src/typeorm/entity/User.ts @@ -1,4 +1,5 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm' +import { UserTransaction } from './UserTransaction' // import { Group } from "./Group" @Entity('state_users') diff --git a/backend/src/typeorm/entity/UserTransaction.ts b/backend/src/typeorm/entity/UserTransaction.ts new file mode 100644 index 000000000..6232c220d --- /dev/null +++ b/backend/src/typeorm/entity/UserTransaction.ts @@ -0,0 +1,35 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp, ManyToOne } from 'typeorm' +import { User } from './User' + + +@Entity('state_user_transactions') +export class UserTransaction extends BaseEntity { + @PrimaryGeneratedColumn() + id: number + + @Column({ name: 'state_user_id' }) + userId: number + + @Column({ name: 'transaction_id' }) + transactionId: number + + @Column({ name: 'transaction_type_id' }) + transactionTypeId: number + + @Column({ name: 'balance', type: 'bigint' }) + balance: number + + @Column({ name: 'balance_date', type: 'timestamp' }) + balanceDate: Timestamp + + static findByUserPaged(userId: number, limit: number, offset: number, order: "ASC" | "DESC") + :Promise<[UserTransaction[], number]> + { + return this.createQueryBuilder('userTransaction') + .where('userTransaction.userId = :userId', { userId }) + .orderBy('userTransaction.balanceDate', order) + .limit(limit) + .offset(offset) + .getManyAndCount() + } +} From eefc506e9767f3313eff438eef1620c819c2deba Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Fri, 24 Sep 2021 12:32:30 +0200 Subject: [PATCH 04/37] linting and use db for db Models --- .../src/graphql/inputs/TransactionInput.ts | 2 +- .../graphql/resolvers/TransactionResolver.ts | 22 ++-- .../src/graphql/resolvers/listTransactions.ts | 102 +++++++++--------- backend/src/typeorm/entity/User.ts | 3 +- backend/src/typeorm/entity/UserTransaction.ts | 25 ++--- 5 files changed, 81 insertions(+), 73 deletions(-) diff --git a/backend/src/graphql/inputs/TransactionInput.ts b/backend/src/graphql/inputs/TransactionInput.ts index 1f79d193e..016fe9720 100644 --- a/backend/src/graphql/inputs/TransactionInput.ts +++ b/backend/src/graphql/inputs/TransactionInput.ts @@ -9,7 +9,7 @@ export class TransactionListInput { items: number @Field(() => String) - order: "ASC" | "DESC" + order: 'ASC' | 'DESC' } @ArgsType() diff --git a/backend/src/graphql/resolvers/TransactionResolver.ts b/backend/src/graphql/resolvers/TransactionResolver.ts index cd17ae993..15de4d145 100644 --- a/backend/src/graphql/resolvers/TransactionResolver.ts +++ b/backend/src/graphql/resolvers/TransactionResolver.ts @@ -6,8 +6,8 @@ import CONFIG from '../../config' import { TransactionList } from '../models/Transaction' import { TransactionListInput, TransactionSendArgs } from '../inputs/TransactionInput' import { apiGet, apiPost } from '../../apis/HttpRequest' -import { User } from '../../typeorm/entity/User' -import { Balance } from '../../typeorm/entity/Balance' +import { User as dbUser } from '../../typeorm/entity/User' +import { Balance as dbBalance } from '../../typeorm/entity/Balance' import listTransactions from './listTransactions' import { roundFloorFrom4 } from '../../util/round' import calculateDecay from '../../util/decay' @@ -25,24 +25,26 @@ export class TransactionResolver { if (!result.success) throw new Error(result.data) // load user - const userEntity = await User.findByPubkeyHex(result.data.user.public_hex) + const userEntity = await dbUser.findByPubkeyHex(result.data.user.public_hex) const transactions = await listTransactions(firstPage, items, order, userEntity) - // get gdt sum - const resultGDTSum = await apiPost( - `${CONFIG.GDT_API_URL}/GdtEntries/sumPerEmailApi`, {email: userEntity.email} - ) + // get gdt sum + const resultGDTSum = await apiPost(`${CONFIG.GDT_API_URL}/GdtEntries/sumPerEmailApi`, { + email: userEntity.email, + }) if (!resultGDTSum.success) throw new Error(resultGDTSum.data) transactions.gdtSum = resultGDTSum.data.sum // get balance - const balanceEntity = await Balance.findByUser(userEntity.id) + const balanceEntity = await dbBalance.findByUser(userEntity.id) const now = new Date() transactions.balance = roundFloorFrom4(balanceEntity.amount) - transactions.decay = roundFloorFrom4(calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now)) + transactions.decay = roundFloorFrom4( + calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now), + ) transactions.decayDate = now.toString() - + return transactions } diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts index a7889a954..ed992fe81 100644 --- a/backend/src/graphql/resolvers/listTransactions.ts +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -1,61 +1,67 @@ - -import { User } from '../../typeorm/entity/User' +import { User as dbUser } from '../../typeorm/entity/User' import { TransactionList, Transaction } from '../models/Transaction' import { UserTransaction } from '../../typeorm/entity/UserTransaction' function calculateAndAddDecayTransactions( - userTransactions:UserTransaction[], - user: User, - decay:boolean, - skipFirstTransaction:boolean -): Transaction[] -{ - let transactions: Transaction[] = [] + userTransactions: UserTransaction[], + user: dbUser, + decay: boolean, + skipFirstTransaction: boolean, +): Transaction[] { + const transactions: Transaction[] = [] - return transactions + return transactions } - export default async function listTransactions( - firstPage:number, - items:number, - order:"ASC" | "DESC", - user:User) : Promise -{ + firstPage: number, + items: number, + order: 'ASC' | 'DESC', + user: dbUser, +): Promise { + let limit = items + let offset = 0 + let skipFirstTransaction = false + if (firstPage > 1) { + offset = (firstPage - 1) * items - 1 + limit++ + } - let limit = items - let offset = 0 - let skipFirstTransaction = false - if(firstPage > 1) { - offset = (( firstPage - 1 ) * items) - 1; - limit++; + if (offset && order === 'ASC') { + offset-- + } + let [userTransactions, userTransactionsCount] = await UserTransaction.findByUserPaged( + user.id, + limit, + offset, + order, + ) + skipFirstTransaction = userTransactionsCount > offset + limit + const decay = !(firstPage > 1) + const transactions: Transaction[] = [] + if (userTransactions.length) { + if (order === 'DESC') { + userTransactions = userTransactions.reverse() } - - if(offset && order == 'ASC') { - offset--; - } - let [userTransactions, userTransactionsCount] = await UserTransaction.findByUserPaged(user.id, limit, offset, order) - skipFirstTransaction = userTransactionsCount > offset + limit - const decay = !(firstPage > 1) - let transactions: Transaction[] = [] - if(userTransactions.length) { - if(order === 'DESC') { - userTransactions = userTransactions.reverse() - } - let transactions = calculateAndAddDecayTransactions(userTransactions, user, decay, skipFirstTransaction) - if(order === 'DESC') { - transactions = transactions.reverse() - } + let transactions = calculateAndAddDecayTransactions( + userTransactions, + user, + decay, + skipFirstTransaction, + ) + if (order === 'DESC') { + transactions = transactions.reverse() } + } - const transactionList = new TransactionList({ - gdtSum: 0, - count: userTransactionsCount, - balance: 0, - decay: 0, - decay_date: '', - transactions: transactions - }) + const transactionList = new TransactionList({ + gdtSum: 0, + count: userTransactionsCount, + balance: 0, + decay: 0, + decay_date: '', + transactions: transactions, + }) - return transactionList -} \ No newline at end of file + return transactionList +} diff --git a/backend/src/typeorm/entity/User.ts b/backend/src/typeorm/entity/User.ts index c675a1d53..cb9de27c8 100644 --- a/backend/src/typeorm/entity/User.ts +++ b/backend/src/typeorm/entity/User.ts @@ -1,5 +1,4 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm' -import { UserTransaction } from './UserTransaction' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' // import { Group } from "./Group" @Entity('state_users') diff --git a/backend/src/typeorm/entity/UserTransaction.ts b/backend/src/typeorm/entity/UserTransaction.ts index 6232c220d..494f57103 100644 --- a/backend/src/typeorm/entity/UserTransaction.ts +++ b/backend/src/typeorm/entity/UserTransaction.ts @@ -1,6 +1,4 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp, ManyToOne } from 'typeorm' -import { User } from './User' - +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp } from 'typeorm' @Entity('state_user_transactions') export class UserTransaction extends BaseEntity { @@ -21,15 +19,18 @@ export class UserTransaction extends BaseEntity { @Column({ name: 'balance_date', type: 'timestamp' }) balanceDate: Timestamp - - static findByUserPaged(userId: number, limit: number, offset: number, order: "ASC" | "DESC") - :Promise<[UserTransaction[], number]> - { + + static findByUserPaged( + userId: number, + limit: number, + offset: number, + order: 'ASC' | 'DESC', + ): Promise<[UserTransaction[], number]> { return this.createQueryBuilder('userTransaction') - .where('userTransaction.userId = :userId', { userId }) - .orderBy('userTransaction.balanceDate', order) - .limit(limit) - .offset(offset) - .getManyAndCount() + .where('userTransaction.userId = :userId', { userId }) + .orderBy('userTransaction.balanceDate', order) + .limit(limit) + .offset(offset) + .getManyAndCount() } } From e80cea5fc4b688244c04e3af480cdfaaf029d184 Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Fri, 24 Sep 2021 13:24:18 +0200 Subject: [PATCH 05/37] add more typeorm models --- backend/src/typeorm/entity/Transaction.ts | 23 ++++++++++++++ .../src/typeorm/entity/TransactionCreation.ts | 25 +++++++++++++++ .../src/typeorm/entity/TransactionSendCoin.ts | 31 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 backend/src/typeorm/entity/Transaction.ts create mode 100644 backend/src/typeorm/entity/TransactionCreation.ts create mode 100644 backend/src/typeorm/entity/TransactionSendCoin.ts diff --git a/backend/src/typeorm/entity/Transaction.ts b/backend/src/typeorm/entity/Transaction.ts new file mode 100644 index 000000000..4fdaf6eb8 --- /dev/null +++ b/backend/src/typeorm/entity/Transaction.ts @@ -0,0 +1,23 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp } from 'typeorm' + +@Entity('transactions') +export class Transaction extends BaseEntity { + @PrimaryGeneratedColumn() + id: number + + @Column({ name: 'transaction_type_id' }) + transactionTypeId: number + + @Column({ name: 'tx_hash', type: 'binary', length: 48 }) + txHash: Buffer + + @Column() + memo: string + + @Column({ type: 'timestamp' }) + received: Timestamp + + @Column({ name: 'blockchain_type_id' }) + blockchainTypeId: number + +} diff --git a/backend/src/typeorm/entity/TransactionCreation.ts b/backend/src/typeorm/entity/TransactionCreation.ts new file mode 100644 index 000000000..ec473a13b --- /dev/null +++ b/backend/src/typeorm/entity/TransactionCreation.ts @@ -0,0 +1,25 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp, OneToOne, JoinColumn } from 'typeorm' +import { Transaction } from './Transaction' + +@Entity('transaction_creations') +export class TransactionCreation extends BaseEntity { + @PrimaryGeneratedColumn() + id: number + + @Column({ name: 'transaction_id' }) + transactionId: number + + @Column({ name: 'state_user_id' }) + userId: number + + @Column() + amount: number + + @Column({ name: 'target_date', type: 'timestamp' }) + targetDate: Timestamp + + @OneToOne(() => Transaction) + @JoinColumn() + transaction: Transaction + +} diff --git a/backend/src/typeorm/entity/TransactionSendCoin.ts b/backend/src/typeorm/entity/TransactionSendCoin.ts new file mode 100644 index 000000000..b5b675d42 --- /dev/null +++ b/backend/src/typeorm/entity/TransactionSendCoin.ts @@ -0,0 +1,31 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm' +import { Transaction } from './Transaction' + +@Entity('transaction_send_coins') +export class TransactionSendCoin extends BaseEntity { + @PrimaryGeneratedColumn() + id: number + + @Column({ name: 'transaction_id' }) + transactionId: number + + @Column({ name: 'sender_public_key', type: 'binary', length: 32 }) + senderPublic: Buffer + + @Column({ name: 'state_user_id' }) + userId: number + + @Column({ name: 'receiver_public_key', type: 'binary', length: 32}) + recipiantPublic: Buffer + + @Column({ name: 'receiver_user_id' }) + recipiantUserId: number + + @Column() + amount: number + + @OneToOne(() => Transaction) + @JoinColumn() + transaction: Transaction + +} From e2f6d1a0068e7ef647a4c2734aa688ba0fc28d05 Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Fri, 24 Sep 2021 14:53:23 +0200 Subject: [PATCH 06/37] work on implementing --- backend/src/graphql/models/Transaction.ts | 28 +++++---- .../src/graphql/resolvers/listTransactions.ts | 60 +++++++++++++++++-- backend/src/typeorm/entity/Transaction.ts | 7 +++ backend/src/typeorm/entity/User.ts | 12 ++++ 4 files changed, 89 insertions(+), 18 deletions(-) diff --git a/backend/src/graphql/models/Transaction.ts b/backend/src/graphql/models/Transaction.ts index a2f2d19c1..7ce7d4494 100644 --- a/backend/src/graphql/models/Transaction.ts +++ b/backend/src/graphql/models/Transaction.ts @@ -10,18 +10,22 @@ import { Decay } from './Decay' @ObjectType() export class Transaction { - constructor(json: any) { - this.type = json.type - this.balance = Number(json.balance) - this.decayStart = json.decay_start - this.decayEnd = json.decay_end - this.decayDuration = json.decay_duration - this.memo = json.memo - this.transactionId = json.transaction_id - this.name = json.name - this.email = json.email - this.date = json.date - this.decay = json.decay ? new Decay(json.decay) : undefined + constructor() + constructor(json: any) + constructor(json?: any) { + if(json) { + this.type = json.type + this.balance = Number(json.balance) + this.decayStart = json.decay_start + this.decayEnd = json.decay_end + this.decayDuration = json.decay_duration + this.memo = json.memo + this.transactionId = json.transaction_id + this.name = json.name + this.email = json.email + this.date = json.date + this.decay = json.decay ? new Decay(json.decay) : undefined + } } @Field(() => String) diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts index ed992fe81..fc4c6de43 100644 --- a/backend/src/graphql/resolvers/listTransactions.ts +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -1,16 +1,64 @@ import { User as dbUser } from '../../typeorm/entity/User' import { TransactionList, Transaction } from '../models/Transaction' -import { UserTransaction } from '../../typeorm/entity/UserTransaction' +import { UserTransaction as dbUserTransaction } from '../../typeorm/entity/UserTransaction' +import { Transaction as dbTransaction } from '../../typeorm/entity/Transaction' +import { TransactionSendCoin as dbTransactionSendCoin} from '../../typeorm/entity/TransactionSendCoin' +import { TransactionCreation as dbTransactionCreation} from '../../typeorm/entity/TransactionCreation' +import calculateDecay from '../../util/decay' +import { roundFloorFrom4 } from '../../util/round' -function calculateAndAddDecayTransactions( - userTransactions: UserTransaction[], +async function calculateAndAddDecayTransactions( + userTransactions: dbUserTransaction[], user: dbUser, decay: boolean, skipFirstTransaction: boolean, -): Transaction[] { - const transactions: Transaction[] = [] +): Promise { + let finalTransactions: Transaction[] = [] + let transactionIds: number[] = [] + let involvedUserIds: number[] = [] - return transactions + userTransactions.forEach((userTransaction: dbUserTransaction) => { + transactionIds.push(userTransaction.transactionId) + involvedUserIds.push(userTransaction.userId) + }) + // remove duplicates + // https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates + const involvedUsersUnique = involvedUserIds.filter((v, i, a) => a.indexOf(v) === i) + const userIndiced = dbUser.getUsersIndiced(involvedUsersUnique) + + const transactions = await dbTransaction + .createQueryBuilder('transaction') + .where('transaction.id IN (:...transactions)', { transactions: transactionIds}) + .leftJoinAndSelect('transaction.sendCoin', 'transactionSendCoin', 'transactionSendCoin.transactionid = transaction.id') + .leftJoinAndSelect('transaction.creation', 'transactionCreation', 'transactionSendCoin.transactionid = transaction.id') + .getMany() + + let transactionIndiced: dbTransaction[] = [] + transactions.forEach((transaction: dbTransaction) => { + transactionIndiced[transaction.id] = transaction + }) + + const decayStartTransaction = await dbTransaction.createQueryBuilder('transaction') + .where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: 9}) + .orderBy('received', 'ASC') + .getOne() + + userTransactions.forEach((userTransaction: dbUserTransaction, i:number) => { + const transaction = transactionIndiced[userTransaction.transactionId] + let finalTransaction = new Transaction + finalTransaction.transactionId = transaction.id + finalTransaction.date = transaction.received.toString() + finalTransaction.memo = transaction.memo + + let prev = i > 0 ? userTransactions[i-1] : null + if(prev && prev.balance > 0) { + + } + + }) + + + return finalTransactions } export default async function listTransactions( diff --git a/backend/src/typeorm/entity/Transaction.ts b/backend/src/typeorm/entity/Transaction.ts index 4fdaf6eb8..c9ecbf29f 100644 --- a/backend/src/typeorm/entity/Transaction.ts +++ b/backend/src/typeorm/entity/Transaction.ts @@ -20,4 +20,11 @@ export class Transaction extends BaseEntity { @Column({ name: 'blockchain_type_id' }) blockchainTypeId: number + static async findByTransactionTypeId(transactionTypeId: number): Promise { + return this.createQueryBuilder('transaction') + .where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: transactionTypeId}) + .getMany() + } + + } diff --git a/backend/src/typeorm/entity/User.ts b/backend/src/typeorm/entity/User.ts index cb9de27c8..e7bca8647 100644 --- a/backend/src/typeorm/entity/User.ts +++ b/backend/src/typeorm/entity/User.ts @@ -32,4 +32,16 @@ export class User extends BaseEntity { .where('hex(user.pubkey) = :pubkeyHex', { pubkeyHex }) .getOneOrFail() } + + static async getUsersIndiced(userIds: number[]): Promise { + const users = await this.createQueryBuilder('user') + .select(['user.id', 'user.firstName', 'user.lastName', 'user.email']) + .where('user.id IN (:...users)', { users: userIds}) + .getMany() + let usersIndiced: User[] = [] + users.forEach((value, index) => { + usersIndiced[index] = value + }) + return usersIndiced + } } From decf4d5013ba55653e6e5337022d3e741a90b194 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 27 Sep 2021 12:24:19 +0200 Subject: [PATCH 07/37] implement at least one special char rule for password in frontend --- .../Inputs/InputPasswordConfirmation.vue | 1 + frontend/src/locales/de.json | 1 + frontend/src/locales/en.json | 1 + frontend/src/validation-rules.js | 7 +++++ frontend/src/views/Pages/Register.spec.js | 10 +++---- .../src/views/Pages/ResetPassword.spec.js | 6 ++-- .../UserCard_FormUserPasswort.spec.js | 29 ++++++++++++------- 7 files changed, 37 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/Inputs/InputPasswordConfirmation.vue b/frontend/src/components/Inputs/InputPasswordConfirmation.vue index 19d4ab02e..d0dc81156 100644 --- a/frontend/src/components/Inputs/InputPasswordConfirmation.vue +++ b/frontend/src/components/Inputs/InputPasswordConfirmation.vue @@ -9,6 +9,7 @@ containsUppercaseCharacter: true, containsNumericCharacter: true, atLeastEightCharactera: true, + atLeastOneSpecialCharater: true, }" :label="register ? $t('form.password') : $t('form.password_new')" :showAllErrors="true" diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 5db1c0a82..be418352e 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -168,6 +168,7 @@ "lowercase": "Ein Kleinbuchstabe erforderlich.", "minimum": "Mindestens 8 Zeichen.", "one_number": "Eine Zahl erforderlich.", + "special-char": "Ein Sonderzeichen required (z.B. _ oder ä)", "subtitle": "Werde Teil der Gemeinschaft!", "title": "Erstelle dein Gradido-Konto", "uppercase": "Ein Großbuchstabe erforderlich." diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 9ca544440..b3148fe3f 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -168,6 +168,7 @@ "lowercase": "One lowercase letter required.", "minimum": "8 characters minimum.", "one_number": "One number required.", + "special-char": "One special character required (e.g. _ or ä)", "subtitle": "Become a part of the community!", "title": "Create your Gradido account", "uppercase": "One uppercase letter required." diff --git a/frontend/src/validation-rules.js b/frontend/src/validation-rules.js index da4e07b78..e836de56b 100644 --- a/frontend/src/validation-rules.js +++ b/frontend/src/validation-rules.js @@ -112,6 +112,13 @@ export const loadAllRules = (i18nCallback) => { message: (_, values) => i18nCallback.t('site.signup.minimum', values), }) + extend('atLeastOneSpecialCharater', { + validate(value) { + return !!value.match(/[^a-zA-Z0-9 \t\n]/) + }, + message: (_, values) => i18nCallback.t('site.signup.special-char', values), + }) + extend('samePassword', { validate(value, [pwd]) { return value === pwd diff --git a/frontend/src/views/Pages/Register.spec.js b/frontend/src/views/Pages/Register.spec.js index a0de965d5..2529b118d 100644 --- a/frontend/src/views/Pages/Register.spec.js +++ b/frontend/src/views/Pages/Register.spec.js @@ -131,8 +131,8 @@ describe('Register', () => { wrapper.find('#registerFirstname').setValue('Max') wrapper.find('#registerLastname').setValue('Mustermann') wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net') - wrapper.find('input[name="form.password"]').setValue('Aa123456') - wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456') + wrapper.find('input[name="form.password"]').setValue('Aa123456_') + wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456_') wrapper.find('.language-switch-select').findAll('option').at(1).setSelected() wrapper.find('input[name="site.signup.agree"]').setChecked(true) }) @@ -185,8 +185,8 @@ describe('Register', () => { wrapper.find('#registerFirstname').setValue('Max') wrapper.find('#registerLastname').setValue('Mustermann') wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net') - wrapper.find('input[name="form.password"]').setValue('Aa123456') - wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456') + wrapper.find('input[name="form.password"]').setValue('Aa123456_') + wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456_') wrapper.find('.language-switch-select').findAll('option').at(1).setSelected() }) @@ -233,7 +233,7 @@ describe('Register', () => { email: 'max.mustermann@gradido.net', firstName: 'Max', lastName: 'Mustermann', - password: 'Aa123456', + password: 'Aa123456_', language: 'de', }, }), diff --git a/frontend/src/views/Pages/ResetPassword.spec.js b/frontend/src/views/Pages/ResetPassword.spec.js index 9f3830a55..a28051502 100644 --- a/frontend/src/views/Pages/ResetPassword.spec.js +++ b/frontend/src/views/Pages/ResetPassword.spec.js @@ -138,8 +138,8 @@ describe('ResetPassword', () => { beforeEach(async () => { await wrapper.setData({ authenticated: true, sessionId: 1 }) await wrapper.vm.$nextTick() - await wrapper.findAll('input').at(0).setValue('Aa123456') - await wrapper.findAll('input').at(1).setValue('Aa123456') + await wrapper.findAll('input').at(0).setValue('Aa123456_') + await wrapper.findAll('input').at(1).setValue('Aa123456_') await flushPromises() await wrapper.find('form').trigger('submit') }) @@ -167,7 +167,7 @@ describe('ResetPassword', () => { variables: { sessionId: 1, email: 'user@example.org', - password: 'Aa123456', + password: 'Aa123456_', }, }), ) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js index fa4aceb0c..7e9703c02 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js @@ -105,12 +105,13 @@ describe('UserCard_FormUserPasswort', () => { describe('validation', () => { it('displays all password requirements', () => { const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') - expect(feedbackArray).toHaveLength(5) + expect(feedbackArray).toHaveLength(6) expect(feedbackArray.at(0).text()).toBe('validations.messages.required') expect(feedbackArray.at(1).text()).toBe('site.signup.lowercase') expect(feedbackArray.at(2).text()).toBe('site.signup.uppercase') expect(feedbackArray.at(3).text()).toBe('site.signup.one_number') expect(feedbackArray.at(4).text()).toBe('site.signup.minimum') + expect(feedbackArray.at(5).text()).toBe('site.signup.special-char') }) it('removes first message when a character is given', async () => { @@ -125,7 +126,7 @@ describe('UserCard_FormUserPasswort', () => { await wrapper.findAll('input').at(1).setValue('a') await flushPromises() const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') - expect(feedbackArray).toHaveLength(3) + expect(feedbackArray).toHaveLength(4) expect(feedbackArray.at(0).text()).toBe('site.signup.uppercase') }) @@ -133,7 +134,7 @@ describe('UserCard_FormUserPasswort', () => { await wrapper.findAll('input').at(1).setValue('Aa') await flushPromises() const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') - expect(feedbackArray).toHaveLength(2) + expect(feedbackArray).toHaveLength(3) expect(feedbackArray.at(0).text()).toBe('site.signup.one_number') }) @@ -141,14 +142,22 @@ describe('UserCard_FormUserPasswort', () => { await wrapper.findAll('input').at(1).setValue('Aa1') await flushPromises() const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') - expect(feedbackArray).toHaveLength(1) + expect(feedbackArray).toHaveLength(2) expect(feedbackArray.at(0).text()).toBe('site.signup.minimum') }) - it('removes all messages when all rules are fulfilled', async () => { + it('removes the first five messages when a eight lowercase, uppercase and numeric characters are given', async () => { await wrapper.findAll('input').at(1).setValue('Aa123456') await flushPromises() const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') + expect(feedbackArray).toHaveLength(1) + expect(feedbackArray.at(0).text()).toBe('site.signup.special-char') + }) + + it('removes all messages when a eight lowercase, uppercase and numeric characters are given', async () => { + await wrapper.findAll('input').at(1).setValue('Aa123456_') + await flushPromises() + const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') expect(feedbackArray).toHaveLength(0) }) }) @@ -164,8 +173,8 @@ describe('UserCard_FormUserPasswort', () => { }, }) await form.findAll('input').at(0).setValue('1234') - await form.findAll('input').at(1).setValue('Aa123456') - await form.findAll('input').at(2).setValue('Aa123456') + await form.findAll('input').at(1).setValue('Aa123456_') + await form.findAll('input').at(2).setValue('Aa123456_') await form.trigger('submit') await flushPromises() }) @@ -176,7 +185,7 @@ describe('UserCard_FormUserPasswort', () => { variables: { email: 'user@example.org', password: '1234', - passwordNew: 'Aa123456', + passwordNew: 'Aa123456_', }, }), ) @@ -197,8 +206,8 @@ describe('UserCard_FormUserPasswort', () => { message: 'error', }) await form.findAll('input').at(0).setValue('1234') - await form.findAll('input').at(1).setValue('Aa123456') - await form.findAll('input').at(2).setValue('Aa123456') + await form.findAll('input').at(1).setValue('Aa123456_') + await form.findAll('input').at(2).setValue('Aa123456_') await form.trigger('submit') await flushPromises() }) From 77b5f9939e8135379ac4623cb7531834d7dcf530 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 27 Sep 2021 12:30:32 +0200 Subject: [PATCH 08/37] fix wrong German translation --- frontend/src/locales/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index be418352e..c7a0946f5 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -168,7 +168,7 @@ "lowercase": "Ein Kleinbuchstabe erforderlich.", "minimum": "Mindestens 8 Zeichen.", "one_number": "Eine Zahl erforderlich.", - "special-char": "Ein Sonderzeichen required (z.B. _ oder ä)", + "special-char": "Ein Sonderzeichen erforderlich (z.B. _ oder ä)", "subtitle": "Werde Teil der Gemeinschaft!", "title": "Erstelle dein Gradido-Konto", "uppercase": "Ein Großbuchstabe erforderlich." From 362f439aaf058a63542c9f5310493da0ac215cb4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 27 Sep 2021 12:58:56 +0200 Subject: [PATCH 09/37] fix: Warnings in Gdd Transaction List Spec --- .../views/Pages/AccountOverview/GddTransactionList.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/views/Pages/AccountOverview/GddTransactionList.spec.js b/frontend/src/views/Pages/AccountOverview/GddTransactionList.spec.js index 5af115546..5418ff3ba 100644 --- a/frontend/src/views/Pages/AccountOverview/GddTransactionList.spec.js +++ b/frontend/src/views/Pages/AccountOverview/GddTransactionList.spec.js @@ -54,7 +54,7 @@ describe('GddTransactionList', () => { await wrapper.setProps({ transactions: [ { - balance: '19.93', + balance: 19.93, date: '2021-05-25T17:38:13+00:00', memo: 'Alles Gute zum Geburtstag', name: 'Bob der Baumeister', @@ -63,7 +63,7 @@ describe('GddTransactionList', () => { decay: { balance: '0.5' }, }, { - balance: '1000', + balance: 1000, date: '2021-04-29T15:34:49+00:00', memo: 'Gut das du da bist!', name: 'Gradido Akademie', @@ -71,7 +71,7 @@ describe('GddTransactionList', () => { type: 'creation', }, { - balance: '314.98', + balance: 314.98, date: '2021-04-29T17:26:40+00:00', memo: 'Für das Fahrrad!', name: 'Jan Ulrich', From 8a7acbf3ce77aa80083df2e986069d7b7ecbd6e8 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 27 Sep 2021 13:09:01 +0200 Subject: [PATCH 10/37] remove unnecessary .* from regexp --- login_server/src/cpp/SingletonManager/SessionManager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/login_server/src/cpp/SingletonManager/SessionManager.cpp b/login_server/src/cpp/SingletonManager/SessionManager.cpp index 13f2a7dd4..1966c6726 100644 --- a/login_server/src/cpp/SingletonManager/SessionManager.cpp +++ b/login_server/src/cpp/SingletonManager/SessionManager.cpp @@ -50,18 +50,18 @@ bool SessionManager::init() case VALIDATE_PASSPHRASE: mValidations[i] = new Poco::RegularExpression("^(?:[a-z]* ){23}[a-z]*\s*$"); break; case VALIDATE_GROUP_ALIAS: mValidations[i] = new Poco::RegularExpression("^[a-z0-9-]{3,120}"); break; case VALIDATE_HEDERA_ID: mValidations[i] = new Poco::RegularExpression("^[0-9]*\.[0-9]*\.[0-9]\.$"); break; - case VALIDATE_HAS_NUMBER: mValidations[i] = new Poco::RegularExpression(".*[0-9].*"); break; + case VALIDATE_HAS_NUMBER: mValidations[i] = new Poco::RegularExpression("[0-9]"); break; case VALIDATE_ONLY_INTEGER: mValidations[i] = new Poco::RegularExpression("^[0-9]*$"); break; case VALIDATE_ONLY_DECIMAL: mValidations[i] = new Poco::RegularExpression("^[0-9]*(\.|,)[0-9]*$"); break; case VALIDATE_ONLY_HEX: mValidations[i] = new Poco::RegularExpression("^(0x)?[a-fA-F0-9]*$"); break; //case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}$"); break; case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\/?"); break; - case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression(".*[^a-zA-Z0-9].*"); break; + case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression("[^a-zA-Z0-9]"); break; case VALIDATE_HAS_UPPERCASE_LETTER: - mValidations[i] = new Poco::RegularExpression(".*[A-Z].*"); + mValidations[i] = new Poco::RegularExpression("[A-Z]"); ServerConfig::g_ServerKeySeed->put(i, DRRandom::r64()); break; - case VALIDATE_HAS_LOWERCASE_LETTER: mValidations[i] = new Poco::RegularExpression(".*[a-z].*"); break; + case VALIDATE_HAS_LOWERCASE_LETTER: mValidations[i] = new Poco::RegularExpression("[a-z]"); break; default: printf("[SessionManager::%s] unknown validation type\n", __FUNCTION__); } } From 9ef5f1e8119aaaa12a95b780ca275a17dab32dcb Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 27 Sep 2021 13:30:18 +0200 Subject: [PATCH 11/37] exclude space, tab, newline from special chars --- login_server/src/cpp/SingletonManager/SessionManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/login_server/src/cpp/SingletonManager/SessionManager.cpp b/login_server/src/cpp/SingletonManager/SessionManager.cpp index 1966c6726..c4039b10d 100644 --- a/login_server/src/cpp/SingletonManager/SessionManager.cpp +++ b/login_server/src/cpp/SingletonManager/SessionManager.cpp @@ -46,7 +46,7 @@ bool SessionManager::init() case VALIDATE_NAME: mValidations[i] = new Poco::RegularExpression("^[^<>&;]{2,}$"); break; case VALIDATE_USERNAME: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z][a-zA-Z0-9_-]*$"); break; case VALIDATE_EMAIL: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z0-9.!#$%&?*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"); break; - case VALIDATE_PASSWORD: mValidations[i] = new Poco::RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9]).{8,}$"); break; + case VALIDATE_PASSWORD: mValidations[i] = new Poco::RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9 \\t\\n\\r]).{8,}$"); break; case VALIDATE_PASSPHRASE: mValidations[i] = new Poco::RegularExpression("^(?:[a-z]* ){23}[a-z]*\s*$"); break; case VALIDATE_GROUP_ALIAS: mValidations[i] = new Poco::RegularExpression("^[a-z0-9-]{3,120}"); break; case VALIDATE_HEDERA_ID: mValidations[i] = new Poco::RegularExpression("^[0-9]*\.[0-9]*\.[0-9]\.$"); break; @@ -56,7 +56,7 @@ bool SessionManager::init() case VALIDATE_ONLY_HEX: mValidations[i] = new Poco::RegularExpression("^(0x)?[a-fA-F0-9]*$"); break; //case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}$"); break; case VALIDATE_ONLY_URL: mValidations[i] = new Poco::RegularExpression("^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\/?"); break; - case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression("[^a-zA-Z0-9]"); break; + case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression("[^a-zA-Z0-9 \\t\\n\\r]"); break; case VALIDATE_HAS_UPPERCASE_LETTER: mValidations[i] = new Poco::RegularExpression("[A-Z]"); ServerConfig::g_ServerKeySeed->put(i, DRRandom::r64()); From d53ef3fc28092d4367ed41d5c4bbd697292423a8 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 27 Sep 2021 13:31:56 +0200 Subject: [PATCH 12/37] entferne 'ein' --- login_server/src/LOCALE/de_DE.mo | Bin 2378 -> 2374 bytes login_server/src/LOCALE/de_DE.po | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/login_server/src/LOCALE/de_DE.mo b/login_server/src/LOCALE/de_DE.mo index 6a1735b6aeff6403fe194c5790665ba6c8fec182..d3d2c86e96c799c6ba3ded9274335f3dd4fac11d 100644 GIT binary patch delta 92 zcmX>lbWCW252I}t0|Ucqb_NDjAZ^CMz@Px6V}P_Ckgf&NDnNP-kk$p#7lE`kkp2&( grGT{d=1#^d%mbV_K052I}#0|Ucqb_NDjAZ^9Lz@Px66M(cHkZuIhDnNPzkk$p#SAn!PkY?s& lV2}dR`kOl$uQ0P4D;SzvnObg6VZFe_tdN?y*_cC^5dg{|51Ie~ diff --git a/login_server/src/LOCALE/de_DE.po b/login_server/src/LOCALE/de_DE.po index 2b97bd88c..b9eea0d59 100644 --- a/login_server/src/LOCALE/de_DE.po +++ b/login_server/src/LOCALE/de_DE.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-09-23 17:56+0200\n" -"PO-Revision-Date: 2021-09-23 17:59+0200\n" +"PO-Revision-Date: 2021-09-27 13:31+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: de_DE\n" @@ -458,7 +458,7 @@ msgid "" "case letters, at least one number and one special character!" msgstr "" "Bitte gebe ein gültiges Password ein mit mindestens 8 Zeichen, Groß- und " -"Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen ein!" +"Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen!" #: src/cpp/SingletonManager/SessionManager.cpp:610 msgid "Your password is to short!" From 342649ae1e8094b3536814f09b7eac8ad31bdf9b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 27 Sep 2021 13:34:58 +0200 Subject: [PATCH 13/37] no white space rule in password --- .../src/components/Inputs/InputPasswordConfirmation.vue | 1 + frontend/src/locales/de.json | 1 + frontend/src/locales/en.json | 1 + frontend/src/validation-rules.js | 9 ++++++++- .../Pages/UserProfile/UserCard_FormUserPasswort.spec.js | 3 ++- 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Inputs/InputPasswordConfirmation.vue b/frontend/src/components/Inputs/InputPasswordConfirmation.vue index d0dc81156..ecb3aa55a 100644 --- a/frontend/src/components/Inputs/InputPasswordConfirmation.vue +++ b/frontend/src/components/Inputs/InputPasswordConfirmation.vue @@ -10,6 +10,7 @@ containsNumericCharacter: true, atLeastEightCharactera: true, atLeastOneSpecialCharater: true, + noWhitespaceCharacters: true, }" :label="register ? $t('form.password') : $t('form.password_new')" :showAllErrors="true" diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index c7a0946f5..f998df196 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -167,6 +167,7 @@ "dont_match": "Die Passwörter stimmen nicht überein.", "lowercase": "Ein Kleinbuchstabe erforderlich.", "minimum": "Mindestens 8 Zeichen.", + "no-whitespace": "Keine Leerzeichen und Tabulatoren", "one_number": "Eine Zahl erforderlich.", "special-char": "Ein Sonderzeichen erforderlich (z.B. _ oder ä)", "subtitle": "Werde Teil der Gemeinschaft!", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index b3148fe3f..e7eba4b93 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -167,6 +167,7 @@ "dont_match": "Passwords don't match.", "lowercase": "One lowercase letter required.", "minimum": "8 characters minimum.", + "no-whitespace": "No white spaces and tabs", "one_number": "One number required.", "special-char": "One special character required (e.g. _ or ä)", "subtitle": "Become a part of the community!", diff --git a/frontend/src/validation-rules.js b/frontend/src/validation-rules.js index e836de56b..9ea954a92 100644 --- a/frontend/src/validation-rules.js +++ b/frontend/src/validation-rules.js @@ -114,11 +114,18 @@ export const loadAllRules = (i18nCallback) => { extend('atLeastOneSpecialCharater', { validate(value) { - return !!value.match(/[^a-zA-Z0-9 \t\n]/) + return !!value.match(/[^a-zA-Z0-9]/) }, message: (_, values) => i18nCallback.t('site.signup.special-char', values), }) + extend('noWhitespaceCharacters', { + validate(value) { + return !!value.match(/[^ \t\n\r]/) + }, + message: (_, values) => i18nCallback.t('site.signup.no-whitespace', values), + }) + extend('samePassword', { validate(value, [pwd]) { return value === pwd diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js index 7e9703c02..a1fa1dd3f 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js @@ -105,13 +105,14 @@ describe('UserCard_FormUserPasswort', () => { describe('validation', () => { it('displays all password requirements', () => { const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') - expect(feedbackArray).toHaveLength(6) + expect(feedbackArray).toHaveLength(7) expect(feedbackArray.at(0).text()).toBe('validations.messages.required') expect(feedbackArray.at(1).text()).toBe('site.signup.lowercase') expect(feedbackArray.at(2).text()).toBe('site.signup.uppercase') expect(feedbackArray.at(3).text()).toBe('site.signup.one_number') expect(feedbackArray.at(4).text()).toBe('site.signup.minimum') expect(feedbackArray.at(5).text()).toBe('site.signup.special-char') + expect(feedbackArray.at(6).text()).toBe('site.signup.no-whitespace') }) it('removes first message when a character is given', async () => { From 5afe8fe741da375e47b4a9bda5d27eb5f15066a0 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 27 Sep 2021 13:35:39 +0200 Subject: [PATCH 14/37] add \r to js regexp --- frontend/src/validation-rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/validation-rules.js b/frontend/src/validation-rules.js index e836de56b..a1c9a46c7 100644 --- a/frontend/src/validation-rules.js +++ b/frontend/src/validation-rules.js @@ -114,7 +114,7 @@ export const loadAllRules = (i18nCallback) => { extend('atLeastOneSpecialCharater', { validate(value) { - return !!value.match(/[^a-zA-Z0-9 \t\n]/) + return !!value.match(/[^a-zA-Z0-9 \t\n\r]/) }, message: (_, values) => i18nCallback.t('site.signup.special-char', values), }) From 713090430fb98ce55050be99ac1438203fdcdbd3 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 27 Sep 2021 15:06:02 +0200 Subject: [PATCH 15/37] feat: Test Change Language in User Profile --- .../UserProfile/UserCard_Language.spec.js | 126 +++++++++++++++++- .../Pages/UserProfile/UserCard_Language.vue | 2 +- 2 files changed, 126 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Language.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_Language.spec.js index 68d0964d3..49134ce91 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Language.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_Language.spec.js @@ -3,7 +3,13 @@ import UserCardLanguage from './UserCard_Language' const localVue = global.localVue -const mockAPIcall = jest.fn() +const mockAPIcall = jest.fn().mockResolvedValue({ + data: { + updateUserInfos: { + validValues: 1, + }, + }, +}) const toastErrorMock = jest.fn() const toastSuccessMock = jest.fn() @@ -17,6 +23,7 @@ describe('UserCard_Language', () => { $store: { state: { language: 'de', + email: 'peter@lustig.de', }, commit: storeCommitMock, }, @@ -27,6 +34,9 @@ describe('UserCard_Language', () => { $apollo: { mutate: mockAPIcall, }, + $i18n: { + locale: 'de', + }, } const Wrapper = () => { @@ -45,5 +55,119 @@ describe('UserCard_Language', () => { it('has an edit icon', () => { expect(wrapper.find('svg.bi-pencil').exists()).toBeTruthy() }) + + it('has change language as text', () => { + expect(wrapper.find('a').text()).toBe('form.changeLanguage') + }) + + it('has no select field by default', () => { + expect(wrapper.find('select').exists()).toBeFalsy() + }) + + describe('edit button', () => { + beforeEach(() => { + wrapper.find('a').trigger('click') + }) + + it('has no edit icon anymore', () => { + expect(wrapper.find('svg.bi-pencil').exists()).toBeFalsy() + }) + + it('has x-circle icon', () => { + expect(wrapper.find('svg.bi-x-circle').exists()).toBeTruthy() + }) + + it('has a submit button', () => { + expect(wrapper.find('button[type="submit"]').exists()).toBeTruthy() + }) + + it('has the submit button disbaled by default', () => { + expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBe('disabled') + }) + + describe('change language', () => { + it('does not enable the submit button when same language is chosen', () => { + wrapper.findAll('option').at(1).setSelected() + expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBe('disabled') + }) + + it('enables the submit button when other language is chosen', async () => { + await wrapper.findAll('option').at(2).setSelected() + expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBe(undefined) + }) + + it('updates language data in component', async () => { + await wrapper.findAll('option').at(2).setSelected() + expect(wrapper.vm.language).toBe('en') + }) + + describe('cancel edit', () => { + beforeEach(async () => { + await wrapper.findAll('option').at(2).setSelected() + wrapper.find('a').trigger('click') + }) + + it('sets the language to initial value', () => { + expect(wrapper.vm.language).toBe('de') + }) + + it('has no select field anymore', () => { + expect(wrapper.find('select').exists()).toBeFalsy() + }) + }) + + describe('submit', () => { + beforeEach(async () => { + await wrapper.findAll('option').at(2).setSelected() + wrapper.find('form').trigger('submit') + }) + + describe('with success', () => { + it('calls the API', () => { + expect(mockAPIcall).toBeCalledWith( + expect.objectContaining({ + variables: { + email: 'peter@lustig.de', + locale: 'en', + }, + }), + ) + }) + + it('commits new language to store', () => { + expect(storeCommitMock).toBeCalledWith('language', 'en') + }) + + it('changes the i18n locale', () => { + expect(mocks.$i18n.locale).toBe('en') + }) + + it('has no select field anymore', () => { + expect(wrapper.find('select').exists()).toBeFalsy() + }) + + it('toasts a success message', () => { + expect(toastSuccessMock).toBeCalledWith('languages.success') + }) + }) + + describe('with error', () => { + beforeEach(() => { + mockAPIcall.mockRejectedValue({ + message: 'Ouch!', + }) + }) + + it('sets the language back to initial value', () => { + expect(wrapper.vm.language).toBe('de') + }) + + it('toasts an error message', () => { + expect(toastErrorMock).toBeCalledWith('Ouch!') + }) + }) + }) + }) + }) }) }) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Language.vue b/frontend/src/views/Pages/UserProfile/UserCard_Language.vue index 2632f8186..d0b13a201 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Language.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_Language.vue @@ -82,6 +82,7 @@ export default { }, cancelEdit() { this.showLanguage = true + this.language = this.$store.state.language }, async onSubmit() { this.$apollo @@ -104,7 +105,6 @@ export default { this.$toasted.error(error.message) }) }, - buildTagFromLanguageString() { return 'languages.' + this.$store.state.language }, From 4dec84321ae11b2b171c62d721ddfe321f6da2ff Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 27 Sep 2021 15:35:17 +0200 Subject: [PATCH 16/37] Cleaned up locales for settings and adjusted texts in files --- .../src/components/LanguageSwitchSelect.vue | 6 +- frontend/src/locales/de.json | 71 ++++++++----------- frontend/src/locales/en.json | 71 ++++++++----------- .../src/views/Pages/ForgotPassword.spec.js | 4 +- frontend/src/views/Pages/ForgotPassword.vue | 6 +- frontend/src/views/Pages/Login.spec.js | 2 +- frontend/src/views/Pages/Login.vue | 2 +- .../src/views/Pages/ResetPassword.spec.js | 12 ++-- frontend/src/views/Pages/ResetPassword.vue | 8 +-- .../UserProfile/UserCard_FormUserData.spec.js | 2 +- .../UserProfile/UserCard_FormUserData.vue | 4 +- .../UserCard_FormUserPasswort.spec.js | 2 +- .../UserProfile/UserCard_FormUserPasswort.vue | 2 +- .../UserProfile/UserCard_FormUsername.spec.js | 2 +- .../UserProfile/UserCard_FormUsername.vue | 2 +- .../Pages/UserProfile/UserCard_Language.vue | 4 +- .../UserProfile/UserCard_Newsletter.spec.js | 2 +- .../Pages/UserProfile/UserCard_Newsletter.vue | 12 ++-- 18 files changed, 96 insertions(+), 118 deletions(-) diff --git a/frontend/src/components/LanguageSwitchSelect.vue b/frontend/src/components/LanguageSwitchSelect.vue index 518bcf6cf..b53b82a18 100644 --- a/frontend/src/components/LanguageSwitchSelect.vue +++ b/frontend/src/components/LanguageSwitchSelect.vue @@ -14,9 +14,9 @@ export default { return { selected: null, options: [ - { value: null, text: this.$t('select_language') }, - { value: 'de', text: this.$t('languages.de') }, - { value: 'en', text: this.$t('languages.en') }, + { value: null, text: this.$t('setting.language.select_language') }, + { value: 'de', text: this.$t('setting.language.de') }, + { value: 'en', text: this.$t('setting.language.en') }, ], } }, diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 2842a6a39..ac9aa89d4 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -45,21 +45,14 @@ "amount": "Betrag", "at": "am", "cancel": "Abbrechen", - "change": "ändern", - "change-name": "Name ändern", - "change-password": "Passwort ändern", - "changeLanguage": "Sprache ändern", - "change_username_info": "Einmal gespeichert, kann der Username ncht mehr geändert werden!", "close": "schließen", "date": "Datum", "description": "Beschreibung", "edit": "bearbeiten", "email": "E-Mail", - "email_repeat": "eMail wiederholen", "firstname": "Vorname", "from": "von", "lastname": "Nachname", - "max_gdd_info": "Maximale anzahl GDD zum versenden erreicht!", "memo": "Nachricht", "message": "Nachricht", "password": "Passwort", @@ -81,12 +74,9 @@ "time": "Zeit", "to": "bis", "to1": "an", - "username": "Username", "validation": { "gddSendAmount": "Das Feld {_field_} muss eine Zahl zwischen {min} und {max} mit höchstens zwei Nachkommastellen sein", - "is-not": "Du kannst dir selbst keine Gradidos überweisen", - "usernmae-regex": "Der Username muss mit einem Buchstaben beginnen auf den mindestens zwei alfanumerische Zeichen folgen müssen.", - "usernmae-unique": "Der Username ist bereits vergeben." + "is-not": "Du kannst dir selbst keine Gradidos überweisen" } }, "gdt": { @@ -106,29 +96,40 @@ }, "imprint": "Impressum", "language": "Sprache", - "languages": { - "de": "Deutsch", - "en": "English", - "success": "Deine Sprache wurde erfolgreich geändert." - }, "login": "Anmeldung", "logout": "Abmelden", "members_area": "Mitgliederbereich", "message": "hallo gradido !!", "privacy_policy": "Datenschutzerklärung", - "reset": "Passwort zurücksetzen", - "reset-password": { - "not-authenticated": "Leider konnten wir dich nicht authentifizieren. Bitte wende dich an den Support.", - "text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünftig in der Gradido-App anmelden kannst.", - "title": "Passwort zurücksetzen" - }, - "select_language": "Bitte wähle eine Sprache für die App und Newsletter", "send": "Senden", "setting": { - "changeNewsletter": "Newsletter Status ändern", - "newsletter": "Newsletter", - "newsletterFalse": "Du bist aus Newslettersystem ausgetragen.", - "newsletterTrue": "Du bist im Newslettersystem eingetraten." + "language": { + "changeLanguage": "Sprache ändern", + "de": "Deutsch", + "en": "English", + "select_language": "Bitte wähle eine Sprache.", + "success": "Deine Sprache wurde erfolgreich geändert." + }, + "name": { + "change-name": "Name ändern", + "change-success": "Dein Name wurde erfolgreich geändert." + }, + "newsletter": { + "newsletter": "Newsletter", + "newsletterFalse": "Du bist aus Newslettersystem ausgetragen.", + "newsletterTrue": "Du bist im Newslettersystem eingetraten." + }, + "password": { + "change-password": "Passwort ändern", + "forgot_pwd": "Passwort vergessen?", + "reset": "Passwort zurücksetzen", + "reset-password": { + "not-authenticated": "Leider konnten wir dich nicht authentifizieren. Bitte wende dich an den Support.", + "text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünftig in der Gradido-App anmelden kannst." + }, + "send_now": "Jetzt senden", + "subtitle": "Wenn du dein Passwort vergessen hast, kannst du es hier zurücksetzen." + } }, "signup": "Registrieren", "site": { @@ -143,28 +144,13 @@ }, "login": { "community": "Tausend Dank, weil du bei uns bist!", - "forgot_pwd": "Passwort vergessen?", "new_wallet": "Neues Konto erstellen", - "remember": "Passwort merken", "signin": "Anmelden" }, "navbar": { - "activity": "Aktivität", "my-profil": "Mein Profil", - "settings": "Einstellungen", "support": "Support" }, - "overview": { - "account_overview": "Kontoübersicht", - "add_work": "neuer Gemeinschaftsbeitrag", - "send_gradido": "Gradido versenden", - "since_last_month": "seid letzten Monat" - }, - "password": { - "send_now": "Jetzt senden", - "subtitle": "Wenn du dein Passwort vergessen hast, kannst du es hier zurücksetzen.", - "title": "Passwort zurücksetzen" - }, "signup": { "agree": "Ich stimme der Datenschutzerklärung zu.", "dont_match": "Die Passwörter stimmen nicht überein.", @@ -192,6 +178,5 @@ "show_all": "Alle {count} Transaktionen ansehen" }, "transactions": "Transaktionen", - "welcome": "Willkommen!", "whitepaper": "Whitepaper" } diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 90faa6b33..1967fc124 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -45,21 +45,14 @@ "amount": "Amount", "at": "at", "cancel": "Cancel", - "change": "change", - "change-name": "Change name", - "change-password": "Change password", - "changeLanguage": "Change language", - "change_username_info": "Once saved, the username cannot be changed again!", "close": "Close", "date": "Date", "description": "Description", "edit": "Edit", "email": "Email", - "email_repeat": "Repeat Email", "firstname": "Firstname", "from": "from", "lastname": "Lastname", - "max_gdd_info": "Maximum number of GDDs to be sent has been reached!", "memo": "Message", "message": "Message", "password": "Password", @@ -81,12 +74,9 @@ "time": "Time", "to": "to", "to1": "to", - "username": "Username", "validation": { "gddSendAmount": "The {_field_} field must be a number between {min} and {max} with at most two digits", - "is-not": "You cannot send Gradidos to yourself", - "usernmae-regex": "The username must start with a letter, followed by at least two alphanumeric characters.", - "usernmae-unique": "The username is already taken." + "is-not": "You cannot send Gradidos to yourself" } }, "gdt": { @@ -106,29 +96,40 @@ }, "imprint": "Legal notice", "language": "Language", - "languages": { - "de": "Deutsch", - "en": "English", - "success": "Your language has been successfully updated." - }, "login": "Login", "logout": "Logout", "members_area": "Member's area", "message": "hello gradido !!", "privacy_policy": "Privacy policy", - "reset": "Reset password", - "reset-password": { - "not-authenticated": "Unfortunately we could not authenticate you. Please contact the support.", - "text": "Now you can save a new password to login to the Gradido-App in the future.", - "title": "Reset Password" - }, - "select_language": "Please choose a language for the app and newsletter", "send": "Send", "setting": { - "changeNewsletter": "Newsletter status change", - "newsletter": "Newsletter", - "newsletterFalse": "You are unsubscribed from newsletter system.", - "newsletterTrue": "You are subscribed to newsletter system." + "language": { + "changeLanguage": "Change language", + "de": "Deutsch", + "en": "English", + "select_language": "Please choose a language.", + "success": "Your language has been successfully updated." + }, + "name": { + "change-name": "Change name", + "change-success": "Your name has been successfully changed." + }, + "newsletter": { + "newsletter": "Newsletter", + "newsletterFalse": "You are unsubscribed from newsletter system.", + "newsletterTrue": "You are subscribed to newsletter system." + }, + "password": { + "change-password": "Change password", + "forgot_pwd": "Forgot password?", + "reset": "Reset password", + "reset-password": { + "not-authenticated": "Unfortunately we could not authenticate you. Please contact the support.", + "text": "Now you can save a new password to login to the Gradido-App in the future." + }, + "send_now": "Send now", + "subtitle": "If you have forgotten your password, you can reset it here." + } }, "signup": "Sign up", "site": { @@ -143,28 +144,13 @@ }, "login": { "community": "A thousand thanks for being with us!", - "forgot_pwd": "Forgot password?", "new_wallet": "Create new account", - "remember": "Remember password", "signin": "Sign in" }, "navbar": { - "activity": "Activity", "my-profil": "My profile", - "settings": "Settings", "support": "Support" }, - "overview": { - "account_overview": "Account overview", - "add_work": "New Community Contribution", - "send_gradido": "Send Gradido", - "since_last_month": "since last month" - }, - "password": { - "send_now": "Send now", - "subtitle": "If you have forgotten your password, you can reset it here.", - "title": "Reset password" - }, "signup": { "agree": "I agree to the privacy policy.", "dont_match": "Passwords don't match.", @@ -192,6 +178,5 @@ "show_all": "View all {count} transactions." }, "transactions": "Transactions", - "welcome": "Welcome!", "whitepaper": "Whitepaper" } diff --git a/frontend/src/views/Pages/ForgotPassword.spec.js b/frontend/src/views/Pages/ForgotPassword.spec.js index d4615c221..5f0311fcb 100644 --- a/frontend/src/views/Pages/ForgotPassword.spec.js +++ b/frontend/src/views/Pages/ForgotPassword.spec.js @@ -39,11 +39,11 @@ describe('ForgotPassword', () => { }) it('has a title', () => { - expect(wrapper.find('h1').text()).toEqual('site.password.title') + expect(wrapper.find('h1').text()).toEqual('setting.password.reset') }) it('has a subtitle', () => { - expect(wrapper.find('p.text-lead').text()).toEqual('site.password.subtitle') + expect(wrapper.find('p.text-lead').text()).toEqual('setting.password.subtitle') }) describe('back button', () => { diff --git a/frontend/src/views/Pages/ForgotPassword.vue b/frontend/src/views/Pages/ForgotPassword.vue index ad56ae95e..c68b94a56 100644 --- a/frontend/src/views/Pages/ForgotPassword.vue +++ b/frontend/src/views/Pages/ForgotPassword.vue @@ -5,8 +5,8 @@
-

{{ $t('site.password.title') }}

-

{{ $t('site.password.subtitle') }}

+

{{ $t('setting.password.reset') }}

+

{{ $t('setting.password.subtitle') }}

@@ -22,7 +22,7 @@
- {{ $t('site.password.send_now') }} + {{ $t('setting.password.send_now') }}
diff --git a/frontend/src/views/Pages/Login.spec.js b/frontend/src/views/Pages/Login.spec.js index 20eead7a3..30f6cb4bd 100644 --- a/frontend/src/views/Pages/Login.spec.js +++ b/frontend/src/views/Pages/Login.spec.js @@ -71,7 +71,7 @@ describe('Login', () => { describe('links', () => { it('has a link "Forgot Password?"', () => { expect(wrapper.findAllComponents(RouterLinkStub).at(0).text()).toEqual( - 'site.login.forgot_pwd', + 'setting.password.forgot_pwd', ) }) diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index e5b365d75..90fa5eb61 100755 --- a/frontend/src/views/Pages/Login.vue +++ b/frontend/src/views/Pages/Login.vue @@ -40,7 +40,7 @@ - {{ $t('site.login.forgot_pwd') }} + {{ $t('setting.password.forgot_pwd') }} diff --git a/frontend/src/views/Pages/ResetPassword.spec.js b/frontend/src/views/Pages/ResetPassword.spec.js index 87198ba62..2df1cd75e 100644 --- a/frontend/src/views/Pages/ResetPassword.spec.js +++ b/frontend/src/views/Pages/ResetPassword.spec.js @@ -71,8 +71,10 @@ describe('ResetPassword', () => { }) it('has a message suggesting to contact the support', () => { - expect(wrapper.find('div.header').text()).toContain('reset-password.title') - expect(wrapper.find('div.header').text()).toContain('reset-password.not-authenticated') + expect(wrapper.find('div.header').text()).toContain('setting.password.reset') + expect(wrapper.find('div.header').text()).toContain( + 'setting.password.reset-password.not-authenticated', + ) }) }) @@ -99,8 +101,10 @@ describe('ResetPassword', () => { describe('Register header', () => { it('has a welcome message', async () => { - expect(wrapper.find('div.header').text()).toContain('reset-password.title') - expect(wrapper.find('div.header').text()).toContain('reset-password.text') + expect(wrapper.find('div.header').text()).toContain('setting.password.reset') + expect(wrapper.find('div.header').text()).toContain( + 'setting.password.reset-password.text', + ) }) }) diff --git a/frontend/src/views/Pages/ResetPassword.vue b/frontend/src/views/Pages/ResetPassword.vue index a9ca9e6c0..f72100600 100644 --- a/frontend/src/views/Pages/ResetPassword.vue +++ b/frontend/src/views/Pages/ResetPassword.vue @@ -5,13 +5,13 @@
-

{{ $t('reset-password.title') }}

+

{{ $t('setting.password.reset') }}

- {{ $t('reset-password.text') }} + {{ $t('setting.password.reset-password.text') }} - {{ $t('reset-password.not-authenticated') }} + {{ $t('setting.password.reset-password.not-authenticated') }}
@@ -29,7 +29,7 @@
- {{ $t('reset') }} + {{ $t('setting.password.reset') }}
diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js index 87bb3edb9..0c7cae799 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js @@ -139,7 +139,7 @@ describe('UserCard_FormUserData', () => { }) it('toasts a success message', () => { - expect(toastSuccessMock).toBeCalledWith('site.profil.user-data.change-success') + expect(toastSuccessMock).toBeCalledWith('setting.name.change-success') }) it('has an edit button again', () => { diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue index abdf9bb19..0cd8ba965 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue @@ -4,7 +4,7 @@ - {{ $t('form.change-name') }} + {{ $t('setting.name.change-name') }} @@ -122,7 +122,7 @@ export default { this.$store.commit('lastName', this.form.lastName) this.$store.commit('description', this.form.description) this.showUserData = true - this.$toasted.success(this.$t('site.profil.user-data.change-success')) + this.$toasted.success(this.$t('setting.name.change-success')) }) .catch((error) => { this.$toasted.error(error.message) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js index dcce66b7f..048f12ff1 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js @@ -47,7 +47,7 @@ describe('UserCard_FormUserPasswort', () => { }) it('has a change password button with text "form.change-password"', () => { - expect(wrapper.find('a').text()).toEqual('form.change-password') + expect(wrapper.find('a').text()).toEqual('setting.password.change-password') }) it('has a change password button with a pencil icon', () => { diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue index f1c531468..5095f7b74 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue @@ -4,7 +4,7 @@ - {{ $t('form.change-password') }} + {{ $t('setting.password.change-password') }} diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js index 1791d326c..4c667d782 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js @@ -125,7 +125,7 @@ describe('UserCard_FormUsername', () => { }) it('toasts an success message', () => { - expect(toastSuccessMock).toBeCalledWith('site.profil.user-data.change-success') + expect(toastSuccessMock).toBeCalledWith('setting.name.change-success') }) it('has no edit button anymore', () => { diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue index 7c100f41f..eae499c07 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue @@ -98,7 +98,7 @@ export default { this.$store.commit('username', this.form.username) this.username = this.form.username this.showUsername = true - this.$toasted.success(this.$t('site.profil.user-data.change-success')) + this.$toasted.success(this.$t('setting.name.change-success')) }) .catch((error) => { this.$toasted.error(error.message) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Language.vue b/frontend/src/views/Pages/UserProfile/UserCard_Language.vue index 2632f8186..0d5872179 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Language.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_Language.vue @@ -4,7 +4,7 @@ - {{ $t('form.changeLanguage') }} + {{ $t('setting.language.changeLanguage') }} @@ -97,7 +97,7 @@ export default { this.$i18n.locale = this.language localeChanged(this.language) this.cancelEdit() - this.$toasted.success(this.$t('languages.success')) + this.$toasted.success(this.$t('setting.language.success')) }) .catch((error) => { this.language = this.$store.state.language diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js index febb47fd6..8f15a855b 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js @@ -74,7 +74,7 @@ describe('UserCard_Newsletter', () => { }) it('toasts a success message', () => { - expect(toastSuccessMock).toBeCalledWith('setting.newsletterFalse') + expect(toastSuccessMock).toBeCalledWith('setting.newsletter.newsletterFalse') }) }) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue index c571ef99a..7b0f124f4 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue @@ -4,7 +4,7 @@ - {{ $t('setting.newsletter') }} + {{ $t('setting.newsletter.newsletter') }} @@ -15,7 +15,11 @@ switch @change="onSubmit" > - {{ newsletterState ? $t('setting.newsletterTrue') : $t('setting.newsletterFalse') }} + {{ + newsletterState + ? $t('setting.newsletter.newsletterTrue') + : $t('setting.newsletter.newsletterFalse') + }} @@ -46,8 +50,8 @@ export default { this.$store.commit('newsletterState', this.newsletterState) this.$toasted.success( this.newsletterState - ? this.$t('setting.newsletterTrue') - : this.$t('setting.newsletterFalse'), + ? this.$t('setting.newsletter.newsletterTrue') + : this.$t('setting.newsletter.newsletterFalse'), ) }) .catch((error) => { From 72ebebd128bd7ecc3678ca0c586b91ab254b01fb Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 27 Sep 2021 16:15:00 +0200 Subject: [PATCH 17/37] line coverage newsletter to 100% --- .../UserProfile/UserCard_Newsletter.spec.js | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js index febb47fd6..37fa63575 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js @@ -1,6 +1,6 @@ import { mount } from '@vue/test-utils' import UserCardNewsletter from './UserCard_Newsletter' -import { unsubscribeNewsletter } from '../../../graphql/mutations' +import { unsubscribeNewsletter, subscribeNewsletter } from '../../../graphql/mutations' const localVue = global.localVue @@ -9,7 +9,6 @@ const mockAPIcall = jest.fn() const toastErrorMock = jest.fn() const toastSuccessMock = jest.fn() const storeCommitMock = jest.fn() -const newsletterStateMock = jest.fn().mockReturnValue(true) describe('UserCard_Newsletter', () => { let wrapper @@ -20,7 +19,7 @@ describe('UserCard_Newsletter', () => { state: { language: 'de', email: 'peter@lustig.de', - newsletterState: newsletterStateMock, + newsletterState: true, }, commit: storeCommitMock, }, @@ -51,13 +50,14 @@ describe('UserCard_Newsletter', () => { }) describe('unsubscribe with sucess', () => { - beforeEach(() => { + beforeEach(async () => { + await wrapper.setData({ newsletterState: false }) mockAPIcall.mockResolvedValue({ data: { unsubscribeNewsletter: true, }, }) - wrapper.find('input').trigger('change') + await wrapper.find('input').trigger('change') }) it('calls the unsubscribe mutation', () => { @@ -78,6 +78,36 @@ describe('UserCard_Newsletter', () => { }) }) + describe('subscribe with sucess', () => { + beforeEach(async () => { + await wrapper.setData({ newsletterState: true }) + mockAPIcall.mockResolvedValue({ + data: { + subscribeNewsletter: true, + }, + }) + wrapper.find('input').trigger('change') + }) + + it('calls the subscribe mutation', () => { + expect(mockAPIcall).toBeCalledWith({ + mutation: subscribeNewsletter, + variables: { + email: 'peter@lustig.de', + language: 'de', + }, + }) + }) + + it('updates the store', () => { + expect(storeCommitMock).toBeCalledWith('newsletterState', true) + }) + + it('toasts a success message', () => { + expect(toastSuccessMock).toBeCalledWith('setting.newsletterFalse') + }) + }) + describe('unsubscribe with server error', () => { beforeEach(() => { mockAPIcall.mockRejectedValue({ From 818234017553075aaf8ef114d5405d5e78b67465 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 27 Sep 2021 16:23:50 +0200 Subject: [PATCH 18/37] coverage unit tests frontend to 69% --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dbf7e807e..850dbc5d9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -344,7 +344,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 67 + min_coverage: 69 token: ${{ github.token }} ############################################################################## From 06c80ebdfd70fc71e398034e1fafc71ffad4fe49 Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Mon, 27 Sep 2021 18:57:36 +0200 Subject: [PATCH 19/37] implement listTransactions and neccessary changes for it --- backend/src/graphql/models/Decay.ts | 31 ++-- backend/src/graphql/models/Transaction.ts | 8 +- .../src/graphql/resolvers/BalanceResolver.ts | 4 +- .../src/graphql/resolvers/listTransactions.ts | 152 +++++++++++++----- backend/src/typeorm/entity/Transaction.ts | 23 ++- .../src/typeorm/entity/TransactionCreation.ts | 13 +- .../src/typeorm/entity/TransactionSendCoin.ts | 5 +- backend/src/typeorm/entity/User.ts | 8 +- backend/src/typeorm/entity/UserTransaction.ts | 4 +- backend/src/util/decay.ts | 53 +++++- 10 files changed, 232 insertions(+), 69 deletions(-) diff --git a/backend/src/graphql/models/Decay.ts b/backend/src/graphql/models/Decay.ts index e0234f588..09564c5ca 100644 --- a/backend/src/graphql/models/Decay.ts +++ b/backend/src/graphql/models/Decay.ts @@ -1,29 +1,42 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { ObjectType, Field, Int } from 'type-graphql' +import { Transaction } from '../../typeorm/entity/Transaction' @ObjectType() export class Decay { - constructor(json: any) { - this.balance = Number(json.balance) - this.decayStart = json.decay_start - this.decayEnd = json.decay_end - this.decayDuration = json.decay_duration - this.decayStartBlock = json.decay_start_block + constructor() + constructor(json?: any) { + if (json) { + this.balance = Number(json.balance) + this.decayStart = json.decay_start + this.decayEnd = json.decay_end + this.decayDuration = json.decay_duration + this.decayStartBlock = json.decay_start_block + } + } + + static async getDecayStartBlock(): Promise { + if (!this.decayStartBlockTransaction) { + this.decayStartBlockTransaction = await Transaction.getDecayStartBlock() + } + return this.decayStartBlockTransaction } @Field(() => Number) balance: number @Field(() => Int, { nullable: true }) - decayStart?: number + decayStart: number @Field(() => Int, { nullable: true }) - decayEnd?: number + decayEnd: number @Field(() => String, { nullable: true }) - decayDuration?: string + decayDuration?: number @Field(() => Int, { nullable: true }) decayStartBlock?: number + + static decayStartBlockTransaction: Transaction | undefined } diff --git a/backend/src/graphql/models/Transaction.ts b/backend/src/graphql/models/Transaction.ts index 7ce7d4494..01dcf280d 100644 --- a/backend/src/graphql/models/Transaction.ts +++ b/backend/src/graphql/models/Transaction.ts @@ -13,19 +13,19 @@ export class Transaction { constructor() constructor(json: any) constructor(json?: any) { - if(json) { + if (json) { this.type = json.type this.balance = Number(json.balance) this.decayStart = json.decay_start this.decayEnd = json.decay_end - this.decayDuration = json.decay_duration + this.decayDuration = parseFloat(json.decay_duration) this.memo = json.memo this.transactionId = json.transaction_id this.name = json.name this.email = json.email this.date = json.date this.decay = json.decay ? new Decay(json.decay) : undefined - } + } } @Field(() => String) @@ -44,7 +44,7 @@ export class Transaction { decayEnd?: number @Field({ nullable: true }) - decayDuration?: string + decayDuration?: number @Field(() => String) memo: string diff --git a/backend/src/graphql/resolvers/BalanceResolver.ts b/backend/src/graphql/resolvers/BalanceResolver.ts index 34aedac37..02c148ffb 100644 --- a/backend/src/graphql/resolvers/BalanceResolver.ts +++ b/backend/src/graphql/resolvers/BalanceResolver.ts @@ -25,7 +25,9 @@ export class BalanceResolver { const now = new Date() const balance = new Balance({ balance: roundFloorFrom4(balanceEntity.amount), - decay: roundFloorFrom4(calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now)), + decay: roundFloorFrom4( + await calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now), + ), decay_date: now.toString(), }) diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts index fc4c6de43..9bbb77bb5 100644 --- a/backend/src/graphql/resolvers/listTransactions.ts +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -2,9 +2,8 @@ import { User as dbUser } from '../../typeorm/entity/User' import { TransactionList, Transaction } from '../models/Transaction' import { UserTransaction as dbUserTransaction } from '../../typeorm/entity/UserTransaction' import { Transaction as dbTransaction } from '../../typeorm/entity/Transaction' -import { TransactionSendCoin as dbTransactionSendCoin} from '../../typeorm/entity/TransactionSendCoin' -import { TransactionCreation as dbTransactionCreation} from '../../typeorm/entity/TransactionCreation' -import calculateDecay from '../../util/decay' +import { Decay } from '../models/Decay' +import { calculateDecayWithInterval } from '../../util/decay' import { roundFloorFrom4 } from '../../util/round' async function calculateAndAddDecayTransactions( @@ -13,9 +12,9 @@ async function calculateAndAddDecayTransactions( decay: boolean, skipFirstTransaction: boolean, ): Promise { - let finalTransactions: Transaction[] = [] - let transactionIds: number[] = [] - let involvedUserIds: number[] = [] + const finalTransactions: Transaction[] = [] + const transactionIds: number[] = [] + const involvedUserIds: number[] = [] userTransactions.forEach((userTransaction: dbUserTransaction) => { transactionIds.push(userTransaction.transactionId) @@ -24,39 +23,120 @@ async function calculateAndAddDecayTransactions( // remove duplicates // https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates const involvedUsersUnique = involvedUserIds.filter((v, i, a) => a.indexOf(v) === i) - const userIndiced = dbUser.getUsersIndiced(involvedUsersUnique) + const userIndiced = await dbUser.getUsersIndiced(involvedUsersUnique) const transactions = await dbTransaction - .createQueryBuilder('transaction') - .where('transaction.id IN (:...transactions)', { transactions: transactionIds}) - .leftJoinAndSelect('transaction.sendCoin', 'transactionSendCoin', 'transactionSendCoin.transactionid = transaction.id') - .leftJoinAndSelect('transaction.creation', 'transactionCreation', 'transactionSendCoin.transactionid = transaction.id') - .getMany() - - let transactionIndiced: dbTransaction[] = [] + .createQueryBuilder('transaction') + .where('transaction.id IN (:...transactions)', { transactions: transactionIds }) + .leftJoinAndSelect( + 'transaction.sendCoin', + 'transactionSendCoin', + 'transactionSendCoin.transactionid = transaction.id', + ) + .leftJoinAndSelect( + 'transaction.creation', + 'transactionCreation', + 'transactionSendCoin.transactionid = transaction.id', + ) + .getMany() + + const transactionIndiced: dbTransaction[] = [] transactions.forEach((transaction: dbTransaction) => { transactionIndiced[transaction.id] = transaction - }) - - const decayStartTransaction = await dbTransaction.createQueryBuilder('transaction') - .where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: 9}) - .orderBy('received', 'ASC') - .getOne() - - userTransactions.forEach((userTransaction: dbUserTransaction, i:number) => { - const transaction = transactionIndiced[userTransaction.transactionId] - let finalTransaction = new Transaction - finalTransaction.transactionId = transaction.id - finalTransaction.date = transaction.received.toString() - finalTransaction.memo = transaction.memo - - let prev = i > 0 ? userTransactions[i-1] : null - if(prev && prev.balance > 0) { - - } - }) + const decayStartTransaction = await Decay.getDecayStartBlock() + + userTransactions.forEach(async (userTransaction: dbUserTransaction, i: number) => { + const transaction = transactionIndiced[userTransaction.transactionId] + const finalTransaction = new Transaction() + finalTransaction.transactionId = transaction.id + finalTransaction.date = transaction.received.toString() + finalTransaction.memo = transaction.memo + finalTransaction.totalBalance = roundFloorFrom4(userTransaction.balance) + + const prev = i > 0 ? userTransactions[i - 1] : null + if (prev && prev.balance > 0) { + const current = userTransaction + const decay = await calculateDecayWithInterval( + prev.balance, + prev.balanceDate, + current.balanceDate, + ) + const balance = prev.balance - decay.balance + + if (balance) { + finalTransaction.decay = decay + finalTransaction.decay.balance = roundFloorFrom4(finalTransaction.decay.balance) + finalTransaction.decay.balance = roundFloorFrom4(balance) + if ( + decayStartTransaction && + prev.transactionId < decayStartTransaction.id && + current.transactionId > decayStartTransaction.id + ) { + finalTransaction.decay.decayStartBlock = decayStartTransaction.received.getTime() + } + } + } + + // sender or receiver when user has sended money + // group name if creation + // type: gesendet / empfangen / geschöpft + // transaktion nr / id + // date + // balance + if (userTransaction.transactionTypeId === 1) { + // creation + const creation = transaction.transactionCreation + + finalTransaction.name = 'Gradido Akademie' + finalTransaction.type = 'creation' + // finalTransaction.targetDate = creation.targetDate + finalTransaction.balance = roundFloorFrom4(creation.amount) + } else if (userTransaction.transactionTypeId === 2) { + // send coin + const sendCoin = transaction.transactionSendCoin + let otherUser: dbUser | undefined + finalTransaction.balance = roundFloorFrom4(sendCoin.amount) + if (sendCoin.userId === user.id) { + finalTransaction.type = 'send' + otherUser = userIndiced[sendCoin.recipiantUserId] + // finalTransaction.pubkey = sendCoin.recipiantPublic + } else if (sendCoin.recipiantUserId === user.id) { + finalTransaction.type = 'receive' + otherUser = userIndiced[sendCoin.userId] + // finalTransaction.pubkey = sendCoin.senderPublic + } else { + throw new Error('invalid transaction') + } + if (otherUser) { + finalTransaction.name = otherUser.firstName + ' ' + otherUser.lastName + finalTransaction.email = otherUser.email + } + } + if (i > 0 || !skipFirstTransaction) { + finalTransactions.push(finalTransaction) + } + if (i === userTransactions.length - 1 && decay) { + const now = new Date() + const decay = await calculateDecayWithInterval( + userTransaction.balance, + userTransaction.balanceDate, + now.getTime(), + ) + const balance = userTransaction.balance - decay.balance + if (balance) { + const decayTransaction = new Transaction() + decayTransaction.type = 'decay' + decayTransaction.balance = roundFloorFrom4(balance) + decayTransaction.decayDuration = decay.decayDuration + decayTransaction.decayStart = decay.decayStart + decayTransaction.decayEnd = decay.decayEnd + finalTransactions.push(decayTransaction) + } + } + return finalTransactions + }) return finalTransactions } @@ -78,7 +158,7 @@ export default async function listTransactions( if (offset && order === 'ASC') { offset-- } - let [userTransactions, userTransactionsCount] = await UserTransaction.findByUserPaged( + let [userTransactions, userTransactionsCount] = await dbUserTransaction.findByUserPaged( user.id, limit, offset, @@ -86,12 +166,12 @@ export default async function listTransactions( ) skipFirstTransaction = userTransactionsCount > offset + limit const decay = !(firstPage > 1) - const transactions: Transaction[] = [] + let transactions: Transaction[] = [] if (userTransactions.length) { if (order === 'DESC') { userTransactions = userTransactions.reverse() } - let transactions = calculateAndAddDecayTransactions( + transactions = await calculateAndAddDecayTransactions( userTransactions, user, decay, diff --git a/backend/src/typeorm/entity/Transaction.ts b/backend/src/typeorm/entity/Transaction.ts index c9ecbf29f..d8b87828c 100644 --- a/backend/src/typeorm/entity/Transaction.ts +++ b/backend/src/typeorm/entity/Transaction.ts @@ -1,4 +1,6 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp } from 'typeorm' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne } from 'typeorm' +import { TransactionCreation } from './TransactionCreation' +import { TransactionSendCoin } from './TransactionSendCoin' @Entity('transactions') export class Transaction extends BaseEntity { @@ -15,16 +17,29 @@ export class Transaction extends BaseEntity { memo: string @Column({ type: 'timestamp' }) - received: Timestamp + received: Date @Column({ name: 'blockchain_type_id' }) blockchainTypeId: number + @OneToOne(() => TransactionSendCoin, (transactionSendCoin) => transactionSendCoin.transaction) + transactionSendCoin: TransactionSendCoin + + @OneToOne(() => TransactionCreation, (transactionCreation) => transactionCreation.transaction) + transactionCreation: TransactionCreation + static async findByTransactionTypeId(transactionTypeId: number): Promise { return this.createQueryBuilder('transaction') - .where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: transactionTypeId}) + .where('transaction.transactionTypeId = :transactionTypeId', { + transactionTypeId: transactionTypeId, + }) .getMany() } - + static async getDecayStartBlock(): Promise { + return this.createQueryBuilder('transaction') + .where('transaction.transactionTypeId = :transactionTypeId', { transactionTypeId: 9 }) + .orderBy('received', 'ASC') + .getOne() + } } diff --git a/backend/src/typeorm/entity/TransactionCreation.ts b/backend/src/typeorm/entity/TransactionCreation.ts index ec473a13b..e9efa2e23 100644 --- a/backend/src/typeorm/entity/TransactionCreation.ts +++ b/backend/src/typeorm/entity/TransactionCreation.ts @@ -1,4 +1,12 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp, OneToOne, JoinColumn } from 'typeorm' +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + Timestamp, + OneToOne, + JoinColumn, +} from 'typeorm' import { Transaction } from './Transaction' @Entity('transaction_creations') @@ -19,7 +27,6 @@ export class TransactionCreation extends BaseEntity { targetDate: Timestamp @OneToOne(() => Transaction) - @JoinColumn() + @JoinColumn() transaction: Transaction - } diff --git a/backend/src/typeorm/entity/TransactionSendCoin.ts b/backend/src/typeorm/entity/TransactionSendCoin.ts index b5b675d42..40ceb298b 100644 --- a/backend/src/typeorm/entity/TransactionSendCoin.ts +++ b/backend/src/typeorm/entity/TransactionSendCoin.ts @@ -15,7 +15,7 @@ export class TransactionSendCoin extends BaseEntity { @Column({ name: 'state_user_id' }) userId: number - @Column({ name: 'receiver_public_key', type: 'binary', length: 32}) + @Column({ name: 'receiver_public_key', type: 'binary', length: 32 }) recipiantPublic: Buffer @Column({ name: 'receiver_user_id' }) @@ -25,7 +25,6 @@ export class TransactionSendCoin extends BaseEntity { amount: number @OneToOne(() => Transaction) - @JoinColumn() + @JoinColumn() transaction: Transaction - } diff --git a/backend/src/typeorm/entity/User.ts b/backend/src/typeorm/entity/User.ts index e7bca8647..e82ba5deb 100644 --- a/backend/src/typeorm/entity/User.ts +++ b/backend/src/typeorm/entity/User.ts @@ -36,12 +36,12 @@ export class User extends BaseEntity { static async getUsersIndiced(userIds: number[]): Promise { const users = await this.createQueryBuilder('user') .select(['user.id', 'user.firstName', 'user.lastName', 'user.email']) - .where('user.id IN (:...users)', { users: userIds}) + .where('user.id IN (:...users)', { users: userIds }) .getMany() - let usersIndiced: User[] = [] - users.forEach((value, index) => { + const usersIndiced: User[] = [] + users.forEach((value, index) => { usersIndiced[index] = value - }) + }) return usersIndiced } } diff --git a/backend/src/typeorm/entity/UserTransaction.ts b/backend/src/typeorm/entity/UserTransaction.ts index 494f57103..1f32dc454 100644 --- a/backend/src/typeorm/entity/UserTransaction.ts +++ b/backend/src/typeorm/entity/UserTransaction.ts @@ -1,4 +1,4 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp } from 'typeorm' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' @Entity('state_user_transactions') export class UserTransaction extends BaseEntity { @@ -18,7 +18,7 @@ export class UserTransaction extends BaseEntity { balance: number @Column({ name: 'balance_date', type: 'timestamp' }) - balanceDate: Timestamp + balanceDate: number static findByUserPaged( userId: number, diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index 44a041a00..ccb6beeb4 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -1,4 +1,51 @@ -export default function (amount: number, from: Date, to: Date): number { - const decayDuration = (to.getTime() - from.getTime()) / 1000 - return amount * Math.pow(0.99999997802044727, decayDuration) +import { Decay } from '../graphql/models/Decay' + +function decayFormula(amount: number, durationInSeconds: number): number { + return amount * Math.pow(0.99999997802044727, durationInSeconds) } + +async function calculateDecay(amount: number, from: Date, to: Date): Promise { + // load decay start block + const decayStartBlock = await Decay.getDecayStartBlock() + + // if decay hasn't started yet we return input amount + if (!decayStartBlock) return amount + + const decayDuration = (to.getTime() - from.getTime()) / 1000 + return decayFormula(amount, decayDuration) +} + +async function calculateDecayWithInterval( + amount: number, + from: number, + to: number, +): Promise { + const decayStartBlock = await Decay.getDecayStartBlock() + const result = new Decay() + result.balance = amount + result.decayStart = from + result.decayEnd = from + + // (amount, from.getTime(), to.getTime()) + + // if no decay start block exist or decay startet after end date + if (decayStartBlock === undefined || decayStartBlock.received.getTime() > to) { + return result + } + + // if decay start date is before start date we calculate decay for full duration + if (decayStartBlock.received.getTime() < from) { + result.decayDuration = to - from + } + // if decay start in between start date and end date we caculcate decay from decay start time to end date + else { + result.decayDuration = to - decayStartBlock.received.getTime() + } + // js use timestamp in milliseconds but we calculate with seconds + result.decayDuration /= 1000 + result.balance = decayFormula(amount, result.decayDuration) + + return result +} + +export { calculateDecay, calculateDecayWithInterval } From 0d33202946c98912c1b89159c356407f208df787 Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Mon, 27 Sep 2021 19:52:46 +0200 Subject: [PATCH 20/37] fix what don't work --- backend/src/graphql/models/Decay.ts | 3 +-- backend/src/graphql/models/Transaction.ts | 2 +- .../src/graphql/resolvers/BalanceResolver.ts | 2 +- .../graphql/resolvers/TransactionResolver.ts | 4 ++-- .../src/graphql/resolvers/listTransactions.ts | 20 +++++++++---------- .../src/typeorm/entity/TransactionCreation.ts | 2 +- .../src/typeorm/entity/TransactionSendCoin.ts | 2 +- backend/src/util/decay.ts | 2 +- 8 files changed, 18 insertions(+), 19 deletions(-) diff --git a/backend/src/graphql/models/Decay.ts b/backend/src/graphql/models/Decay.ts index 09564c5ca..9bc89f6ec 100644 --- a/backend/src/graphql/models/Decay.ts +++ b/backend/src/graphql/models/Decay.ts @@ -5,8 +5,7 @@ import { Transaction } from '../../typeorm/entity/Transaction' @ObjectType() export class Decay { - constructor() - constructor(json?: any) { + constructor(json: any) { if (json) { this.balance = Number(json.balance) this.decayStart = json.decay_start diff --git a/backend/src/graphql/models/Transaction.ts b/backend/src/graphql/models/Transaction.ts index 01dcf280d..c34cac1c5 100644 --- a/backend/src/graphql/models/Transaction.ts +++ b/backend/src/graphql/models/Transaction.ts @@ -18,7 +18,7 @@ export class Transaction { this.balance = Number(json.balance) this.decayStart = json.decay_start this.decayEnd = json.decay_end - this.decayDuration = parseFloat(json.decay_duration) + this.memo = json.memo this.transactionId = json.transaction_id this.name = json.name diff --git a/backend/src/graphql/resolvers/BalanceResolver.ts b/backend/src/graphql/resolvers/BalanceResolver.ts index 02c148ffb..e7e8d73a3 100644 --- a/backend/src/graphql/resolvers/BalanceResolver.ts +++ b/backend/src/graphql/resolvers/BalanceResolver.ts @@ -7,7 +7,7 @@ import { Balance } from '../models/Balance' import { apiGet } from '../../apis/HttpRequest' import { User as dbUser } from '../../typeorm/entity/User' import { Balance as dbBalance } from '../../typeorm/entity/Balance' -import calculateDecay from '../../util/decay' +import { calculateDecay } from '../../util/decay' import { roundFloorFrom4 } from '../../util/round' @Resolver() diff --git a/backend/src/graphql/resolvers/TransactionResolver.ts b/backend/src/graphql/resolvers/TransactionResolver.ts index 0e4106991..f8cf2db62 100644 --- a/backend/src/graphql/resolvers/TransactionResolver.ts +++ b/backend/src/graphql/resolvers/TransactionResolver.ts @@ -10,7 +10,7 @@ import { User as dbUser } from '../../typeorm/entity/User' import { Balance as dbBalance } from '../../typeorm/entity/Balance' import listTransactions from './listTransactions' import { roundFloorFrom4 } from '../../util/round' -import calculateDecay from '../../util/decay' +import { calculateDecay } from '../../util/decay' @Resolver() export class TransactionResolver { @@ -41,7 +41,7 @@ export class TransactionResolver { const now = new Date() transactions.balance = roundFloorFrom4(balanceEntity.amount) transactions.decay = roundFloorFrom4( - calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now), + await calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now), ) transactions.decayDate = now.toString() diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts index 9bbb77bb5..73ddea150 100644 --- a/backend/src/graphql/resolvers/listTransactions.ts +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -12,7 +12,7 @@ async function calculateAndAddDecayTransactions( decay: boolean, skipFirstTransaction: boolean, ): Promise { - const finalTransactions: Transaction[] = [] + let finalTransactions: Transaction[] = [] const transactionIds: number[] = [] const involvedUserIds: number[] = [] @@ -29,14 +29,14 @@ async function calculateAndAddDecayTransactions( .createQueryBuilder('transaction') .where('transaction.id IN (:...transactions)', { transactions: transactionIds }) .leftJoinAndSelect( - 'transaction.sendCoin', - 'transactionSendCoin', - 'transactionSendCoin.transactionid = transaction.id', + 'transaction.transactionSendCoin', + 'transactionSendCoin' + //'transactionSendCoin.transaction_id = transaction.id', ) .leftJoinAndSelect( - 'transaction.creation', - 'transactionCreation', - 'transactionSendCoin.transactionid = transaction.id', + 'transaction.transactionCreation', + 'transactionCreation' + //'transactionSendCoin.transaction_id = transaction.id', ) .getMany() @@ -47,7 +47,7 @@ async function calculateAndAddDecayTransactions( const decayStartTransaction = await Decay.getDecayStartBlock() - userTransactions.forEach(async (userTransaction: dbUserTransaction, i: number) => { + await userTransactions.forEach(async (userTransaction: dbUserTransaction, i: number) => { const transaction = transactionIndiced[userTransaction.transactionId] const finalTransaction = new Transaction() finalTransaction.transactionId = transaction.id @@ -117,6 +117,7 @@ async function calculateAndAddDecayTransactions( if (i > 0 || !skipFirstTransaction) { finalTransactions.push(finalTransaction) } + if (i === userTransactions.length - 1 && decay) { const now = new Date() const decay = await calculateDecayWithInterval( @@ -135,7 +136,6 @@ async function calculateAndAddDecayTransactions( finalTransactions.push(decayTransaction) } } - return finalTransactions }) return finalTransactions @@ -176,7 +176,7 @@ export default async function listTransactions( user, decay, skipFirstTransaction, - ) + ) if (order === 'DESC') { transactions = transactions.reverse() } diff --git a/backend/src/typeorm/entity/TransactionCreation.ts b/backend/src/typeorm/entity/TransactionCreation.ts index e9efa2e23..4a8bdd571 100644 --- a/backend/src/typeorm/entity/TransactionCreation.ts +++ b/backend/src/typeorm/entity/TransactionCreation.ts @@ -27,6 +27,6 @@ export class TransactionCreation extends BaseEntity { targetDate: Timestamp @OneToOne(() => Transaction) - @JoinColumn() + @JoinColumn({ name: 'transaction_id' }) transaction: Transaction } diff --git a/backend/src/typeorm/entity/TransactionSendCoin.ts b/backend/src/typeorm/entity/TransactionSendCoin.ts index 40ceb298b..4054ea755 100644 --- a/backend/src/typeorm/entity/TransactionSendCoin.ts +++ b/backend/src/typeorm/entity/TransactionSendCoin.ts @@ -25,6 +25,6 @@ export class TransactionSendCoin extends BaseEntity { amount: number @OneToOne(() => Transaction) - @JoinColumn() + @JoinColumn({ name: 'transaction_id' }) transaction: Transaction } diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index ccb6beeb4..6b07cb35f 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -21,7 +21,7 @@ async function calculateDecayWithInterval( to: number, ): Promise { const decayStartBlock = await Decay.getDecayStartBlock() - const result = new Decay() + const result = new Decay(undefined) result.balance = amount result.decayStart = from result.decayEnd = from From 01ea24099acfb98f3990d2db3ad9f215c051eb1c Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 27 Sep 2021 21:26:07 +0200 Subject: [PATCH 21/37] warnings throw errors when running unit tests --- frontend/test/testSetup.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/test/testSetup.js b/frontend/test/testSetup.js index 7005ff5be..daf862548 100644 --- a/frontend/test/testSetup.js +++ b/frontend/test/testSetup.js @@ -1,6 +1,7 @@ import { createLocalVue } from '@vue/test-utils' import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' import Vuex from 'vuex' +import Vue from 'vue' import { ValidationProvider, ValidationObserver, extend } from 'vee-validate' import * as rules from 'vee-validate/dist/rules' @@ -47,3 +48,8 @@ global.localVue.component('validation-provider', ValidationProvider) global.localVue.component('validation-observer', ValidationObserver) global.localVue.directive('click-outside', clickOutside) global.localVue.directive('focus', focus) + +// throw errors for vue warnings to force the programmers to take care about warnings +Vue.config.warnHandler = (w) => { + throw new Error(w) +} From 3d2e87470c14e910e24bac049748b4e13a5839b6 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 27 Sep 2021 23:07:02 +0200 Subject: [PATCH 22/37] fix: Whitespace in Password Shows Validation Error --- frontend/src/validation-rules.js | 4 ++-- .../Pages/UserProfile/UserCard_FormUserPasswort.spec.js | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/frontend/src/validation-rules.js b/frontend/src/validation-rules.js index 9ea954a92..5552794d1 100644 --- a/frontend/src/validation-rules.js +++ b/frontend/src/validation-rules.js @@ -114,14 +114,14 @@ export const loadAllRules = (i18nCallback) => { extend('atLeastOneSpecialCharater', { validate(value) { - return !!value.match(/[^a-zA-Z0-9]/) + return !!value.match(/[^a-zA-Z0-9 \t\n\r]/) }, message: (_, values) => i18nCallback.t('site.signup.special-char', values), }) extend('noWhitespaceCharacters', { validate(value) { - return !!value.match(/[^ \t\n\r]/) + return !value.match(/[ \t\n\r]+/) }, message: (_, values) => i18nCallback.t('site.signup.no-whitespace', values), }) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js index 1b5c97e72..8c3c1341b 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js @@ -105,13 +105,20 @@ describe('UserCard_FormUserPasswort', () => { describe('validation', () => { it('displays all password requirements', () => { const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') - expect(feedbackArray).toHaveLength(7) + expect(feedbackArray).toHaveLength(6) expect(feedbackArray.at(0).text()).toBe('validations.messages.required') expect(feedbackArray.at(1).text()).toBe('site.signup.lowercase') expect(feedbackArray.at(2).text()).toBe('site.signup.uppercase') expect(feedbackArray.at(3).text()).toBe('site.signup.one_number') expect(feedbackArray.at(4).text()).toBe('site.signup.minimum') expect(feedbackArray.at(5).text()).toBe('site.signup.special-char') + }) + + it('displays no whitespace error when a space character is entered', async () => { + await wrapper.findAll('input').at(1).setValue(' ') + await flushPromises() + const feedbackArray = wrapper.findAll('div.invalid-feedback').at(1).findAll('span') + expect(feedbackArray).toHaveLength(7) expect(feedbackArray.at(6).text()).toBe('site.signup.no-whitespace') }) From f5915d0ada3123d2b208c42a4221cf9ad5ff4b13 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 28 Sep 2021 09:41:07 +0200 Subject: [PATCH 23/37] setting changed to settings, remove delete rows --- frontend/src/components/LanguageSwitchSelect.vue | 6 +++--- frontend/src/locales/de.json | 6 ++++-- frontend/src/locales/en.json | 6 ++++-- frontend/src/views/Pages/ForgotPassword.spec.js | 4 ++-- frontend/src/views/Pages/ForgotPassword.vue | 6 +++--- frontend/src/views/Pages/Login.spec.js | 2 +- frontend/src/views/Pages/Login.vue | 2 +- frontend/src/views/Pages/ResetPassword.spec.js | 8 ++++---- frontend/src/views/Pages/ResetPassword.vue | 8 ++++---- .../Pages/UserProfile/UserCard_FormUserData.spec.js | 2 +- .../views/Pages/UserProfile/UserCard_FormUserData.vue | 4 ++-- .../UserProfile/UserCard_FormUserPasswort.spec.js | 2 +- .../Pages/UserProfile/UserCard_FormUserPasswort.vue | 2 +- .../Pages/UserProfile/UserCard_FormUsername.spec.js | 2 +- .../views/Pages/UserProfile/UserCard_FormUsername.vue | 2 +- .../src/views/Pages/UserProfile/UserCard_Language.vue | 4 ++-- .../Pages/UserProfile/UserCard_Newsletter.spec.js | 2 +- .../views/Pages/UserProfile/UserCard_Newsletter.vue | 10 +++++----- 18 files changed, 41 insertions(+), 37 deletions(-) diff --git a/frontend/src/components/LanguageSwitchSelect.vue b/frontend/src/components/LanguageSwitchSelect.vue index b53b82a18..c547d9af3 100644 --- a/frontend/src/components/LanguageSwitchSelect.vue +++ b/frontend/src/components/LanguageSwitchSelect.vue @@ -14,9 +14,9 @@ export default { return { selected: null, options: [ - { value: null, text: this.$t('setting.language.select_language') }, - { value: 'de', text: this.$t('setting.language.de') }, - { value: 'en', text: this.$t('setting.language.en') }, + { value: null, text: this.$t('settings.language.select_language') }, + { value: 'de', text: this.$t('settings.language.de') }, + { value: 'en', text: this.$t('settings.language.en') }, ], } }, diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index ac9aa89d4..b43f4b4e5 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -76,7 +76,9 @@ "to1": "an", "validation": { "gddSendAmount": "Das Feld {_field_} muss eine Zahl zwischen {min} und {max} mit höchstens zwei Nachkommastellen sein", - "is-not": "Du kannst dir selbst keine Gradidos überweisen" + "is-not": "Du kannst dir selbst keine Gradidos überweisen", + "usernmae-regex": "Der Username muss mit einem Buchstaben beginnen auf den mindestens zwei alfanumerische Zeichen folgen müssen.", + "usernmae-unique": "Der Username ist bereits vergeben." } }, "gdt": { @@ -102,7 +104,7 @@ "message": "hallo gradido !!", "privacy_policy": "Datenschutzerklärung", "send": "Senden", - "setting": { + "settings": { "language": { "changeLanguage": "Sprache ändern", "de": "Deutsch", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 1967fc124..8dda1dfbe 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -76,7 +76,9 @@ "to1": "to", "validation": { "gddSendAmount": "The {_field_} field must be a number between {min} and {max} with at most two digits", - "is-not": "You cannot send Gradidos to yourself" + "is-not": "You cannot send Gradidos to yourself", + "usernmae-regex": "The username must start with a letter, followed by at least two alphanumeric characters.", + "usernmae-unique": "The username is already taken." } }, "gdt": { @@ -102,7 +104,7 @@ "message": "hello gradido !!", "privacy_policy": "Privacy policy", "send": "Send", - "setting": { + "settings": { "language": { "changeLanguage": "Change language", "de": "Deutsch", diff --git a/frontend/src/views/Pages/ForgotPassword.spec.js b/frontend/src/views/Pages/ForgotPassword.spec.js index 5f0311fcb..91247d8a6 100644 --- a/frontend/src/views/Pages/ForgotPassword.spec.js +++ b/frontend/src/views/Pages/ForgotPassword.spec.js @@ -39,11 +39,11 @@ describe('ForgotPassword', () => { }) it('has a title', () => { - expect(wrapper.find('h1').text()).toEqual('setting.password.reset') + expect(wrapper.find('h1').text()).toEqual('settings.password.reset') }) it('has a subtitle', () => { - expect(wrapper.find('p.text-lead').text()).toEqual('setting.password.subtitle') + expect(wrapper.find('p.text-lead').text()).toEqual('settings.password.subtitle') }) describe('back button', () => { diff --git a/frontend/src/views/Pages/ForgotPassword.vue b/frontend/src/views/Pages/ForgotPassword.vue index c68b94a56..444e94495 100644 --- a/frontend/src/views/Pages/ForgotPassword.vue +++ b/frontend/src/views/Pages/ForgotPassword.vue @@ -5,8 +5,8 @@
-

{{ $t('setting.password.reset') }}

-

{{ $t('setting.password.subtitle') }}

+

{{ $t('settings.password.reset') }}

+

{{ $t('settings.password.subtitle') }}

@@ -22,7 +22,7 @@
- {{ $t('setting.password.send_now') }} + {{ $t('settings.password.send_now') }}
diff --git a/frontend/src/views/Pages/Login.spec.js b/frontend/src/views/Pages/Login.spec.js index 30f6cb4bd..7218384f7 100644 --- a/frontend/src/views/Pages/Login.spec.js +++ b/frontend/src/views/Pages/Login.spec.js @@ -71,7 +71,7 @@ describe('Login', () => { describe('links', () => { it('has a link "Forgot Password?"', () => { expect(wrapper.findAllComponents(RouterLinkStub).at(0).text()).toEqual( - 'setting.password.forgot_pwd', + 'settings.password.forgot_pwd', ) }) diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index 90fa5eb61..f5c6f025d 100755 --- a/frontend/src/views/Pages/Login.vue +++ b/frontend/src/views/Pages/Login.vue @@ -40,7 +40,7 @@ - {{ $t('setting.password.forgot_pwd') }} + {{ $t('settings.password.forgot_pwd') }} diff --git a/frontend/src/views/Pages/ResetPassword.spec.js b/frontend/src/views/Pages/ResetPassword.spec.js index 2df1cd75e..bd1467524 100644 --- a/frontend/src/views/Pages/ResetPassword.spec.js +++ b/frontend/src/views/Pages/ResetPassword.spec.js @@ -71,9 +71,9 @@ describe('ResetPassword', () => { }) it('has a message suggesting to contact the support', () => { - expect(wrapper.find('div.header').text()).toContain('setting.password.reset') + expect(wrapper.find('div.header').text()).toContain('settings.password.reset') expect(wrapper.find('div.header').text()).toContain( - 'setting.password.reset-password.not-authenticated', + 'settings.password.reset-password.not-authenticated', ) }) }) @@ -101,9 +101,9 @@ describe('ResetPassword', () => { describe('Register header', () => { it('has a welcome message', async () => { - expect(wrapper.find('div.header').text()).toContain('setting.password.reset') + expect(wrapper.find('div.header').text()).toContain('settings.password.reset') expect(wrapper.find('div.header').text()).toContain( - 'setting.password.reset-password.text', + 'settings.password.reset-password.text', ) }) }) diff --git a/frontend/src/views/Pages/ResetPassword.vue b/frontend/src/views/Pages/ResetPassword.vue index f72100600..81b3d7df7 100644 --- a/frontend/src/views/Pages/ResetPassword.vue +++ b/frontend/src/views/Pages/ResetPassword.vue @@ -5,13 +5,13 @@
-

{{ $t('setting.password.reset') }}

+

{{ $t('settings.password.reset') }}

- {{ $t('setting.password.reset-password.text') }} + {{ $t('settings.password.reset-password.text') }} - {{ $t('setting.password.reset-password.not-authenticated') }} + {{ $t('settings.password.reset-password.not-authenticated') }}
@@ -29,7 +29,7 @@
- {{ $t('setting.password.reset') }} + {{ $t('settings.password.reset') }}
diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js index 0c7cae799..927f1d29d 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js @@ -139,7 +139,7 @@ describe('UserCard_FormUserData', () => { }) it('toasts a success message', () => { - expect(toastSuccessMock).toBeCalledWith('setting.name.change-success') + expect(toastSuccessMock).toBeCalledWith('settings.name.change-success') }) it('has an edit button again', () => { diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue index 0cd8ba965..b3cee1ef5 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue @@ -4,7 +4,7 @@ - {{ $t('setting.name.change-name') }} + {{ $t('settings.name.change-name') }} @@ -122,7 +122,7 @@ export default { this.$store.commit('lastName', this.form.lastName) this.$store.commit('description', this.form.description) this.showUserData = true - this.$toasted.success(this.$t('setting.name.change-success')) + this.$toasted.success(this.$t('settings.name.change-success')) }) .catch((error) => { this.$toasted.error(error.message) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js index 048f12ff1..372a1ba1f 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js @@ -47,7 +47,7 @@ describe('UserCard_FormUserPasswort', () => { }) it('has a change password button with text "form.change-password"', () => { - expect(wrapper.find('a').text()).toEqual('setting.password.change-password') + expect(wrapper.find('a').text()).toEqual('settings.password.change-password') }) it('has a change password button with a pencil icon', () => { diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue index 5095f7b74..1f6c34c26 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue @@ -4,7 +4,7 @@ - {{ $t('setting.password.change-password') }} + {{ $t('settings.password.change-password') }} diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js index 4c667d782..a55c223d7 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js @@ -125,7 +125,7 @@ describe('UserCard_FormUsername', () => { }) it('toasts an success message', () => { - expect(toastSuccessMock).toBeCalledWith('setting.name.change-success') + expect(toastSuccessMock).toBeCalledWith('settings.name.change-success') }) it('has no edit button anymore', () => { diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue index eae499c07..f9d46bbba 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue @@ -98,7 +98,7 @@ export default { this.$store.commit('username', this.form.username) this.username = this.form.username this.showUsername = true - this.$toasted.success(this.$t('setting.name.change-success')) + this.$toasted.success(this.$t('settings.name.change-success')) }) .catch((error) => { this.$toasted.error(error.message) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Language.vue b/frontend/src/views/Pages/UserProfile/UserCard_Language.vue index 0d5872179..8d05620c9 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Language.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_Language.vue @@ -4,7 +4,7 @@ - {{ $t('setting.language.changeLanguage') }} + {{ $t('settings.language.changeLanguage') }} @@ -97,7 +97,7 @@ export default { this.$i18n.locale = this.language localeChanged(this.language) this.cancelEdit() - this.$toasted.success(this.$t('setting.language.success')) + this.$toasted.success(this.$t('settings.language.success')) }) .catch((error) => { this.language = this.$store.state.language diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js index 8f15a855b..3a70840e1 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js @@ -74,7 +74,7 @@ describe('UserCard_Newsletter', () => { }) it('toasts a success message', () => { - expect(toastSuccessMock).toBeCalledWith('setting.newsletter.newsletterFalse') + expect(toastSuccessMock).toBeCalledWith('settings.newsletter.newsletterFalse') }) }) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue index 7b0f124f4..31fd745b2 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue @@ -4,7 +4,7 @@ - {{ $t('setting.newsletter.newsletter') }} + {{ $t('settings.newsletter.newsletter') }} @@ -17,8 +17,8 @@ > {{ newsletterState - ? $t('setting.newsletter.newsletterTrue') - : $t('setting.newsletter.newsletterFalse') + ? $t('settings.newsletter.newsletterTrue') + : $t('settings.newsletter.newsletterFalse') }} @@ -50,8 +50,8 @@ export default { this.$store.commit('newsletterState', this.newsletterState) this.$toasted.success( this.newsletterState - ? this.$t('setting.newsletter.newsletterTrue') - : this.$t('setting.newsletter.newsletterFalse'), + ? this.$t('settings.newsletter.newsletterTrue') + : this.$t('settings.newsletter.newsletterFalse'), ) }) .catch((error) => { From 1a42aa17e4827da7fcbd7f7efe051d39fc8bc20d Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 28 Sep 2021 12:29:45 +0200 Subject: [PATCH 24/37] register process simplified, reset function removed, submit button replaced with disable function --- frontend/src/views/Pages/Register.spec.js | 62 ++--------------------- frontend/src/views/Pages/Register.vue | 37 +++++--------- 2 files changed, 16 insertions(+), 83 deletions(-) diff --git a/frontend/src/views/Pages/Register.spec.js b/frontend/src/views/Pages/Register.spec.js index 8c00d5bd6..233897243 100644 --- a/frontend/src/views/Pages/Register.spec.js +++ b/frontend/src/views/Pages/Register.spec.js @@ -55,11 +55,11 @@ describe('Register', () => { describe('links', () => { it('has a link "Back"', () => { - expect(wrapper.findAllComponents(RouterLinkStub).at(0).text()).toEqual('back') + expect(wrapper.find('.test-button-back').text()).toEqual('back') }) it('links to /login when clicking "Back"', () => { - expect(wrapper.findAllComponents(RouterLinkStub).at(0).props().to).toBe('/login') + expect(wrapper.find('.test-button-back').props().to).toBe('/login') }) }) @@ -98,8 +98,8 @@ describe('Register', () => { expect(wrapper.find('#registerCheckbox').exists()).toBeTruthy() }) - it('has no submit button when not completely filled', () => { - expect(wrapper.find('button[type="submit"]').exists()).toBe(false) + it('has disabled submit button when not completely filled', () => { + expect(wrapper.find('button[type="submit"]').is('[disabled]')).toBe(true) }) it('displays a message that Email is required', async () => { @@ -127,60 +127,6 @@ describe('Register', () => { }) }) - describe('resetForm', () => { - beforeEach(() => { - wrapper.find('#registerFirstname').setValue('Max') - wrapper.find('#registerLastname').setValue('Mustermann') - wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net') - wrapper.find('input[name="form.password"]').setValue('Aa123456_') - wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456_') - wrapper.find('.language-switch-select').findAll('option').at(1).setSelected() - wrapper.find('input[name="site.signup.agree"]').setChecked(true) - }) - - it('reset selected value language', async () => { - await wrapper.find('button.ml-2').trigger('click') - await flushPromises() - expect(wrapper.find('.language-switch-select').element.value).toBe(undefined) - }) - - it('resets the firstName field after clicking the reset button', async () => { - await wrapper.find('button.ml-2').trigger('click') - await flushPromises() - expect(wrapper.find('#registerFirstname').element.value).toBe('') - }) - - it('resets the lastName field after clicking the reset button', async () => { - await wrapper.find('button.ml-2').trigger('click') - await flushPromises() - expect(wrapper.find('#registerLastname').element.value).toBe('') - }) - - it('resets the email field after clicking the reset button', async () => { - await wrapper.find('button.ml-2').trigger('click') - await flushPromises() - expect(wrapper.find('#Email-input-field').element.value).toBe('') - }) - - it.skip('resets the password field after clicking the reset button', async () => { - await wrapper.find('button.ml-2').trigger('click') - await flushPromises() - expect(wrapper.find('input[name="form.password"]').element.value).toBe('') - }) - - it.skip('resets the passwordRepeat field after clicking the reset button', async () => { - await wrapper.find('button.ml-2').trigger('click') - await flushPromises() - expect(wrapper.find('input[name="form.passwordRepeat"]').element.value).toBe('') - }) - - it('resets the firstName field after clicking the reset button', async () => { - await wrapper.find('button.ml-2').trigger('click') - await flushPromises() - expect(wrapper.find('input[name="site.signup.agree"]').props.checked).not.toBeTruthy() - }) - }) - describe('API calls', () => { beforeEach(() => { wrapper.find('#registerFirstname').setValue('Max') diff --git a/frontend/src/views/Pages/Register.vue b/frontend/src/views/Pages/Register.vue index 1a1b91bbe..89b539922 100755 --- a/frontend/src/views/Pages/Register.vue +++ b/frontend/src/views/Pages/Register.vue @@ -116,13 +116,19 @@ -
+
- {{ $t('form.reset') }} - {{ $t('signup') }} + + {{ $t('back') }} + + + + {{ $t('signup') }} +
@@ -131,9 +137,6 @@ -
- {{ $t('back') }} -
@@ -172,22 +175,6 @@ export default { getValidationState({ dirty, validated, valid = null }) { return dirty || validated ? valid : null }, - resetForm() { - this.form = { - firstname: '', - lastname: '', - email: '', - password: { - password: '', - passwordRepeat: '', - }, - agree: false, - } - this.language = '' - this.$nextTick(() => { - this.$refs.observer.reset() - }) - }, async onSubmit() { this.$apollo .mutate({ From aa2565d294328dc74070d9c3dffdef974b6a259c Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Tue, 28 Sep 2021 13:11:22 +0200 Subject: [PATCH 25/37] debugging stuff --- backend/src/graphql/resolvers/listTransactions.ts | 11 +++++++++-- backend/src/util/decay.ts | 1 - 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts index 73ddea150..21516bb87 100644 --- a/backend/src/graphql/resolvers/listTransactions.ts +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -54,8 +54,8 @@ async function calculateAndAddDecayTransactions( finalTransaction.date = transaction.received.toString() finalTransaction.memo = transaction.memo finalTransaction.totalBalance = roundFloorFrom4(userTransaction.balance) - const prev = i > 0 ? userTransactions[i - 1] : null + if (prev && prev.balance > 0) { const current = userTransaction const decay = await calculateDecayWithInterval( @@ -63,12 +63,17 @@ async function calculateAndAddDecayTransactions( prev.balanceDate, current.balanceDate, ) + console.log("decay: %o for transaction %o", decay, i) const balance = prev.balance - decay.balance + console.log("balance: %o", balance) if (balance) { finalTransaction.decay = decay - finalTransaction.decay.balance = roundFloorFrom4(finalTransaction.decay.balance) + console.log("final transaction decay: %o", decay) + console.log("round balance: %o", balance) finalTransaction.decay.balance = roundFloorFrom4(balance) + console.log("final transaction decay: %o after setting balance", decay) + console.log("rounded: %o", finalTransaction.decay.balance) if ( decayStartTransaction && prev.transactionId < decayStartTransaction.id && @@ -76,6 +81,8 @@ async function calculateAndAddDecayTransactions( ) { finalTransaction.decay.decayStartBlock = decayStartTransaction.received.getTime() } + } else { + console.log("balance isn't true: %o", balance) } } diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index 6b07cb35f..1d92e8cec 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -44,7 +44,6 @@ async function calculateDecayWithInterval( // js use timestamp in milliseconds but we calculate with seconds result.decayDuration /= 1000 result.balance = decayFormula(amount, result.decayDuration) - return result } From e1197c5a6cbe68d7b5ed6961443d5ca78e10ce2a Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 28 Sep 2021 13:44:05 +0200 Subject: [PATCH 26/37] removed LOGIN_API_URL & COMMUNITY_API_URL from frontend config --- frontend/src/config/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index 54c2c7aeb..96f7795ce 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -18,8 +18,6 @@ const environment = { } const server = { - LOGIN_API_URL: process.env.LOGIN_API_URL || 'http://localhost/login_api/', - COMMUNITY_API_URL: process.env.COMMUNITY_API_URL || 'http://localhost/api/', GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000/graphql', } From 01abcce931776d98a95074ff14dbf12ae47f319b Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 28 Sep 2021 13:44:30 +0200 Subject: [PATCH 27/37] removed LOGIN_API_URL & COMMUNITY_API_URL from .env.dist --- frontend/.env.dist | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/.env.dist b/frontend/.env.dist index 1252faf5b..a7d67f970 100644 --- a/frontend/.env.dist +++ b/frontend/.env.dist @@ -1,5 +1,3 @@ -LOGIN_API_URL=http://localhost/login_api/ -COMMUNITY_API_URL=http://localhost/api/ ALLOW_REGISTER=true GRAPHQL_URI=http://localhost:4000/graphql //BUILD_COMMIT=0000000 \ No newline at end of file From a8faa7b51b7bbf56024d07924a79e4c333cb6f12 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 28 Sep 2021 13:47:22 +0200 Subject: [PATCH 28/37] add test - enable disable button on submit register --- frontend/src/views/Pages/Register.spec.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/Pages/Register.spec.js b/frontend/src/views/Pages/Register.spec.js index 233897243..04e59cde6 100644 --- a/frontend/src/views/Pages/Register.spec.js +++ b/frontend/src/views/Pages/Register.spec.js @@ -99,7 +99,7 @@ describe('Register', () => { }) it('has disabled submit button when not completely filled', () => { - expect(wrapper.find('button[type="submit"]').is('[disabled]')).toBe(true) + expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBe('disabled') }) it('displays a message that Email is required', async () => { @@ -137,6 +137,10 @@ describe('Register', () => { wrapper.find('.language-switch-select').findAll('option').at(1).setSelected() }) + it('has enabled submit button when completely filled', () => { + expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBe('disabled') + }) + describe('server sends back error', () => { beforeEach(async () => { registerUserMutationMock.mockRejectedValue({ message: 'Ouch!' }) From a0583cbb503d5fed06094e46bfb41c6931bf6638 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 28 Sep 2021 14:27:59 +0200 Subject: [PATCH 29/37] fix: Double Redirect After Logout with Expired JWT --- frontend/src/views/Layout/DashboardLayout_gdd.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/Layout/DashboardLayout_gdd.vue b/frontend/src/views/Layout/DashboardLayout_gdd.vue index 35e7bb8af..8784b4312 100755 --- a/frontend/src/views/Layout/DashboardLayout_gdd.vue +++ b/frontend/src/views/Layout/DashboardLayout_gdd.vue @@ -101,7 +101,7 @@ export default { .catch(() => { this.$sidebar.displaySidebar(false) this.$store.dispatch('logout') - this.$router.push('/login') + if (this.$router.currentRoute.path !== '/login') this.$router.push('/login') }) }, async updateTransactions(pagination) { From fd2ae0f2429a1cf12435a05412b76d5dca5f90e1 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 28 Sep 2021 14:55:14 +0200 Subject: [PATCH 30/37] remove select 'null' in LanguageSwitchSelect.vue --- frontend/src/components/LanguageSwitchSelect.vue | 1 - frontend/src/locales/de.json | 1 - frontend/src/locales/en.json | 1 - frontend/src/views/Pages/Register.spec.js | 4 ++-- frontend/src/views/Pages/Register.vue | 2 +- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/LanguageSwitchSelect.vue b/frontend/src/components/LanguageSwitchSelect.vue index 518bcf6cf..3467bdafd 100644 --- a/frontend/src/components/LanguageSwitchSelect.vue +++ b/frontend/src/components/LanguageSwitchSelect.vue @@ -14,7 +14,6 @@ export default { return { selected: null, options: [ - { value: null, text: this.$t('select_language') }, { value: 'de', text: this.$t('languages.de') }, { value: 'en', text: this.$t('languages.en') }, ], diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 468c88f85..6dbd06fbd 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -122,7 +122,6 @@ "text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünftig in der Gradido-App anmelden kannst.", "title": "Passwort zurücksetzen" }, - "select_language": "Bitte wähle eine Sprache für die App und Newsletter", "send": "Senden", "setting": { "changeNewsletter": "Newsletter Status ändern", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 05ce82b7b..39578936d 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -122,7 +122,6 @@ "text": "Now you can save a new password to login to the Gradido-App in the future.", "title": "Reset Password" }, - "select_language": "Please choose a language for the app and newsletter", "send": "Send", "setting": { "changeNewsletter": "Newsletter status change", diff --git a/frontend/src/views/Pages/Register.spec.js b/frontend/src/views/Pages/Register.spec.js index 04e59cde6..37ee22f78 100644 --- a/frontend/src/views/Pages/Register.spec.js +++ b/frontend/src/views/Pages/Register.spec.js @@ -91,7 +91,7 @@ describe('Register', () => { }) it('selected Language value de', async () => { wrapper.find('.selectedLanguage').findAll('option').at(1).setSelected() - expect(wrapper.find('.selectedLanguage').element.value).toBe('de') + expect(wrapper.find('.selectedLanguage').element.value).toBe('en') }) it('has 1 checkbox input fields', () => { @@ -185,7 +185,7 @@ describe('Register', () => { firstName: 'Max', lastName: 'Mustermann', password: 'Aa123456_', - language: 'de', + language: 'en', }, }), ) diff --git a/frontend/src/views/Pages/Register.vue b/frontend/src/views/Pages/Register.vue index 89b539922..f08ea286e 100755 --- a/frontend/src/views/Pages/Register.vue +++ b/frontend/src/views/Pages/Register.vue @@ -225,7 +225,7 @@ export default { return this.form.email !== '' }, languageFilled() { - return this.language !== null && this.language !== '' + return !!this.language }, }, } From 9cecec97b0ac3d234745bd82141a50b8b52362d4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 28 Sep 2021 15:41:45 +0200 Subject: [PATCH 31/37] test is no entering the catch block after logout fail --- .../views/Layout/DashboardLayout_gdd.spec.js | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/frontend/src/views/Layout/DashboardLayout_gdd.spec.js b/frontend/src/views/Layout/DashboardLayout_gdd.spec.js index d59942a2e..2a789b329 100644 --- a/frontend/src/views/Layout/DashboardLayout_gdd.spec.js +++ b/frontend/src/views/Layout/DashboardLayout_gdd.spec.js @@ -32,6 +32,9 @@ describe('DashboardLayoutGdd', () => { }, $router: { push: routerPushMock, + currentRoute: { + path: '/overview', + }, }, $toasted: { error: toasterMock, @@ -143,21 +146,23 @@ describe('DashboardLayoutGdd', () => { it('redirects to login page', () => { expect(routerPushMock).toBeCalledWith('/login') }) + }) - describe('logout fails', () => { - beforeEach(() => { - apolloMock.mockRejectedValue({ - message: 'error', - }) + describe('logout fails', () => { + beforeEach(async () => { + apolloMock.mockRejectedValue({ + message: 'error', }) + await wrapper.findComponent({ name: 'sidebar' }).vm.$emit('logout') + await flushPromises() + }) - it('dispatches logout to store', () => { - expect(storeDispatchMock).toBeCalledWith('logout') - }) + it('dispatches logout to store', () => { + expect(storeDispatchMock).toBeCalledWith('logout') + }) - it('redirects to login page', () => { - expect(routerPushMock).toBeCalledWith('/login') - }) + it('redirects to login page', () => { + expect(routerPushMock).toBeCalledWith('/login') }) }) From 6883fc37785e994683b756f3011438694d96b988 Mon Sep 17 00:00:00 2001 From: Alexander Friedland Date: Tue, 28 Sep 2021 16:40:47 +0200 Subject: [PATCH 32/37] Update Register.spec.js --- frontend/src/views/Pages/Register.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/Pages/Register.spec.js b/frontend/src/views/Pages/Register.spec.js index 37ee22f78..f3f66fca9 100644 --- a/frontend/src/views/Pages/Register.spec.js +++ b/frontend/src/views/Pages/Register.spec.js @@ -25,7 +25,7 @@ describe('Register', () => { $store: { state: { email: 'peter@lustig.de', - language: null, + language: 'en', }, }, } @@ -89,7 +89,7 @@ describe('Register', () => { it('has Language selected field', () => { expect(wrapper.find('.selectedLanguage').exists()).toBeTruthy() }) - it('selected Language value de', async () => { + it('selects Language value en', async () => { wrapper.find('.selectedLanguage').findAll('option').at(1).setSelected() expect(wrapper.find('.selectedLanguage').element.value).toBe('en') }) From ef0db3cb02bde14e33931ba33511392b23ec16e7 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Tue, 28 Sep 2021 16:56:10 +0200 Subject: [PATCH 33/37] fix linting --- .../src/graphql/resolvers/BalanceResolver.ts | 23 +++++++++++++------ .../graphql/resolvers/TransactionResolver.ts | 14 ++++++----- .../src/graphql/resolvers/listTransactions.ts | 22 ++++++------------ backend/src/typeorm/entity/Balance.ts | 6 ++--- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/backend/src/graphql/resolvers/BalanceResolver.ts b/backend/src/graphql/resolvers/BalanceResolver.ts index e7e8d73a3..f31b66371 100644 --- a/backend/src/graphql/resolvers/BalanceResolver.ts +++ b/backend/src/graphql/resolvers/BalanceResolver.ts @@ -22,14 +22,23 @@ export class BalanceResolver { // load user and balance const userEntity = await dbUser.findByPubkeyHex(result.data.user.public_hex) const balanceEntity = await dbBalance.findByUser(userEntity.id) + let balance: Balance const now = new Date() - const balance = new Balance({ - balance: roundFloorFrom4(balanceEntity.amount), - decay: roundFloorFrom4( - await calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now), - ), - decay_date: now.toString(), - }) + if (balanceEntity) { + balance = new Balance({ + balance: roundFloorFrom4(balanceEntity.amount), + decay: roundFloorFrom4( + await calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now), + ), + decay_date: now.toString(), + }) + } else { + balance = new Balance({ + balance: 0, + decay: 0, + decay_date: now.toString(), + }) + } return balance } diff --git a/backend/src/graphql/resolvers/TransactionResolver.ts b/backend/src/graphql/resolvers/TransactionResolver.ts index f8cf2db62..3762cccee 100644 --- a/backend/src/graphql/resolvers/TransactionResolver.ts +++ b/backend/src/graphql/resolvers/TransactionResolver.ts @@ -38,12 +38,14 @@ export class TransactionResolver { // get balance const balanceEntity = await dbBalance.findByUser(userEntity.id) - const now = new Date() - transactions.balance = roundFloorFrom4(balanceEntity.amount) - transactions.decay = roundFloorFrom4( - await calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now), - ) - transactions.decayDate = now.toString() + if (balanceEntity) { + const now = new Date() + transactions.balance = roundFloorFrom4(balanceEntity.amount) + transactions.decay = roundFloorFrom4( + await calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now), + ) + transactions.decayDate = now.toString() + } return transactions } diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts index 21516bb87..8c4519776 100644 --- a/backend/src/graphql/resolvers/listTransactions.ts +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -12,7 +12,7 @@ async function calculateAndAddDecayTransactions( decay: boolean, skipFirstTransaction: boolean, ): Promise { - let finalTransactions: Transaction[] = [] + const finalTransactions: Transaction[] = [] const transactionIds: number[] = [] const involvedUserIds: number[] = [] @@ -30,13 +30,13 @@ async function calculateAndAddDecayTransactions( .where('transaction.id IN (:...transactions)', { transactions: transactionIds }) .leftJoinAndSelect( 'transaction.transactionSendCoin', - 'transactionSendCoin' - //'transactionSendCoin.transaction_id = transaction.id', + 'transactionSendCoin', + // 'transactionSendCoin.transaction_id = transaction.id', ) .leftJoinAndSelect( 'transaction.transactionCreation', - 'transactionCreation' - //'transactionSendCoin.transaction_id = transaction.id', + 'transactionCreation', + // 'transactionSendCoin.transaction_id = transaction.id', ) .getMany() @@ -63,17 +63,11 @@ async function calculateAndAddDecayTransactions( prev.balanceDate, current.balanceDate, ) - console.log("decay: %o for transaction %o", decay, i) const balance = prev.balance - decay.balance - console.log("balance: %o", balance) if (balance) { finalTransaction.decay = decay - console.log("final transaction decay: %o", decay) - console.log("round balance: %o", balance) finalTransaction.decay.balance = roundFloorFrom4(balance) - console.log("final transaction decay: %o after setting balance", decay) - console.log("rounded: %o", finalTransaction.decay.balance) if ( decayStartTransaction && prev.transactionId < decayStartTransaction.id && @@ -81,8 +75,6 @@ async function calculateAndAddDecayTransactions( ) { finalTransaction.decay.decayStartBlock = decayStartTransaction.received.getTime() } - } else { - console.log("balance isn't true: %o", balance) } } @@ -124,7 +116,7 @@ async function calculateAndAddDecayTransactions( if (i > 0 || !skipFirstTransaction) { finalTransactions.push(finalTransaction) } - + if (i === userTransactions.length - 1 && decay) { const now = new Date() const decay = await calculateDecayWithInterval( @@ -183,7 +175,7 @@ export default async function listTransactions( user, decay, skipFirstTransaction, - ) + ) if (order === 'DESC') { transactions = transactions.reverse() } diff --git a/backend/src/typeorm/entity/Balance.ts b/backend/src/typeorm/entity/Balance.ts index 1cde6bcc2..23b21de78 100644 --- a/backend/src/typeorm/entity/Balance.ts +++ b/backend/src/typeorm/entity/Balance.ts @@ -17,9 +17,7 @@ export class Balance extends BaseEntity { @Column({ type: 'bigint' }) amount: number - static findByUser(userId: number): Promise { - return this.createQueryBuilder('balance') - .where('balance.userId = :userId', { userId }) - .getOneOrFail() + static findByUser(userId: number): Promise { + return this.createQueryBuilder('balance').where('balance.userId = :userId', { userId }).getOne() } } From aa27f02d467643baa17113effa34ed900794bf05 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 28 Sep 2021 20:12:02 +0200 Subject: [PATCH 34/37] fix type in describe block --- .../src/views/Pages/UserProfile/UserCard_Newsletter.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js index 37fa63575..042964d9d 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js @@ -49,7 +49,7 @@ describe('UserCard_Newsletter', () => { expect(wrapper.find('.Test-BFormCheckbox').exists()).toBeTruthy() }) - describe('unsubscribe with sucess', () => { + describe('unsubscribe with success', () => { beforeEach(async () => { await wrapper.setData({ newsletterState: false }) mockAPIcall.mockResolvedValue({ @@ -78,7 +78,7 @@ describe('UserCard_Newsletter', () => { }) }) - describe('subscribe with sucess', () => { + describe('subscribe with success', () => { beforeEach(async () => { await wrapper.setData({ newsletterState: true }) mockAPIcall.mockResolvedValue({ From dba6a1b8d654fd376ca286cb2726184953841d41 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 29 Sep 2021 12:02:16 +0200 Subject: [PATCH 35/37] change datatype for timestamps to string --- backend/package-lock.json | 4712 ----------------- backend/src/graphql/models/Decay.ts | 8 +- backend/src/graphql/models/Transaction.ts | 40 +- .../graphql/resolvers/TransactionResolver.ts | 1 - .../src/graphql/resolvers/listTransactions.ts | 16 +- backend/src/typeorm/entity/UserTransaction.ts | 2 +- backend/src/util/decay.ts | 18 +- 7 files changed, 35 insertions(+), 4762 deletions(-) delete mode 100644 backend/package-lock.json diff --git a/backend/package-lock.json b/backend/package-lock.json deleted file mode 100644 index 44ff1180f..000000000 --- a/backend/package-lock.json +++ /dev/null @@ -1,4712 +0,0 @@ -{ - "name": "gradido-backend", - "version": "1.4.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@apollo/protobufjs": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.2.tgz", - "integrity": "sha512-vF+zxhPiLtkwxONs6YanSt1EpwpGilThpneExUN5K3tCymuxNnVq2yojTvnpRjv2QfsEIt/n7ozPIIzBLwGIDQ==", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.0", - "@types/node": "^10.1.0", - "long": "^4.0.0" - }, - "dependencies": { - "@types/node": { - "version": "10.17.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", - "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" - } - } - }, - "@apollographql/apollo-tools": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.5.1.tgz", - "integrity": "sha512-ZII+/xUFfb9ezDU2gad114+zScxVFMVlZ91f8fGApMzlS1kkqoyLnC4AJaQ1Ya/X+b63I20B4Gd+eCL8QuB4sA==" - }, - "@apollographql/graphql-playground-html": { - "version": "1.6.27", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.27.tgz", - "integrity": "sha512-tea2LweZvn6y6xFV11K0KC8ETjmm52mQrW+ezgB2O/aTQf8JGyFmMcRPFgUaQZeHbWdm8iisDC6EjOKsXu0nfw==", - "requires": { - "xss": "^1.0.8" - } - }, - "@apollographql/graphql-upload-8-fork": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/@apollographql/graphql-upload-8-fork/-/graphql-upload-8-fork-8.1.3.tgz", - "integrity": "sha512-ssOPUT7euLqDXcdVv3Qs4LoL4BPtfermW1IOouaqEmj36TpHYDmYDIbKoSQxikd9vtMumFnP87OybH7sC9fJ6g==", - "requires": { - "@types/express": "*", - "@types/fs-capacitor": "*", - "@types/koa": "*", - "busboy": "^0.3.1", - "fs-capacitor": "^2.0.4", - "http-errors": "^1.7.3", - "object-path": "^0.11.4" - } - }, - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", - "dev": true - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - } - } - }, - "@eslint/eslintrc": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", - "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@josephg/resolvable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@josephg/resolvable/-/resolvable-1.0.1.tgz", - "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==" - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, - "@sqltools/formatter": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.3.tgz", - "integrity": "sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg==" - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.1.tgz", - "integrity": "sha512-FTgBI767POY/lKNDNbIzgAX6miIDBs6NTCbdlDb8TrWovHsSvaVIZDlTqym29C6UqhzwcJx4CYr+AlrMywA0cA==", - "dev": true - }, - "@types/accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@types/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ==" - }, - "@types/cookies": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.7.7.tgz", - "integrity": "sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==", - "requires": { - "@types/connect": "*", - "@types/express": "*", - "@types/keygrip": "*", - "@types/node": "*" - } - }, - "@types/cors": { - "version": "2.8.10", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", - "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", - "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/fs-capacitor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/fs-capacitor/-/fs-capacitor-2.0.0.tgz", - "integrity": "sha512-FKVPOCFbhCvZxpVAMhdBdTfVfXUpsh15wFHgqOKxh9N9vzWZVuWCSijZ5T4U34XYNnuj2oduh6xcs1i+LPI+BQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/http-assert": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.1.tgz", - "integrity": "sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ==" - }, - "@types/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-e+2rjEwK6KDaNOm5Aa9wNGgyS9oSZU/4pfSMMPYNOfjvFI0WVXm29+ITRFr6aKDvvKo7uU1jV68MW4ScsfDi7Q==" - }, - "@types/json-schema": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz", - "integrity": "sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "@types/jsonwebtoken": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.2.tgz", - "integrity": "sha512-X8BOCkp+WJVNYCYIBugREtVZa4Y09Or9HDx6xqRZem5F8jJV8FuJgNessXyMuv9+U8pjnvdezASwU28uw+1scw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/keygrip": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.2.tgz", - "integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==" - }, - "@types/koa": { - "version": "2.13.4", - "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.13.4.tgz", - "integrity": "sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw==", - "requires": { - "@types/accepts": "*", - "@types/content-disposition": "*", - "@types/cookies": "*", - "@types/http-assert": "*", - "@types/http-errors": "*", - "@types/keygrip": "*", - "@types/koa-compose": "*", - "@types/node": "*" - } - }, - "@types/koa-compose": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.5.tgz", - "integrity": "sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==", - "requires": { - "@types/koa": "*" - } - }, - "@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" - }, - "@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" - }, - "@types/node": { - "version": "15.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.4.tgz", - "integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "@types/semver": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.6.tgz", - "integrity": "sha512-0caWDWmpCp0uifxFh+FaqK3CuZ2SkRR/ZRxAV5+zNdC3QVUi6wyOJnefhPvtNt8NQWXB5OA93BUvZsXpWat2Xw==" - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/validator": { - "version": "13.6.3", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.6.3.tgz", - "integrity": "sha512-fWG42pMJOL4jKsDDZZREnXLjc3UE0R8LOJfARWYg6U966rxDT7TYejYzLnUF5cvSObGg34nd0+H2wHHU5Omdfw==" - }, - "@types/ws": { - "version": "7.4.7", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", - "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", - "requires": { - "@types/node": "*" - } - }, - "@types/zen-observable": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz", - "integrity": "sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==" - }, - "@typescript-eslint/eslint-plugin": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.0.tgz", - "integrity": "sha512-KcF6p3zWhf1f8xO84tuBailV5cN92vhS+VT7UJsPzGBm9VnQqfI9AsiMUFUCYHTYPg1uCCo+HyiDnpDuvkAMfQ==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "4.28.0", - "@typescript-eslint/scope-manager": "4.28.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.0.tgz", - "integrity": "sha512-9XD9s7mt3QWMk82GoyUpc/Ji03vz4T5AYlHF9DcoFNfJ/y3UAclRsfGiE2gLfXtyC+JRA3trR7cR296TEb1oiQ==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.28.0", - "@typescript-eslint/types": "4.28.0", - "@typescript-eslint/typescript-estree": "4.28.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "dependencies": { - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - } - } - }, - "@typescript-eslint/parser": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.0.tgz", - "integrity": "sha512-7x4D22oPY8fDaOCvkuXtYYTQ6mTMmkivwEzS+7iml9F9VkHGbbZ3x4fHRwxAb5KeuSkLqfnYjs46tGx2Nour4A==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "4.28.0", - "@typescript-eslint/types": "4.28.0", - "@typescript-eslint/typescript-estree": "4.28.0", - "debug": "^4.3.1" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@typescript-eslint/scope-manager": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.0.tgz", - "integrity": "sha512-eCALCeScs5P/EYjwo6se9bdjtrh8ByWjtHzOkC4Tia6QQWtQr3PHovxh3TdYTuFcurkYI4rmFsRFpucADIkseg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.28.0", - "@typescript-eslint/visitor-keys": "4.28.0" - } - }, - "@typescript-eslint/types": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.0.tgz", - "integrity": "sha512-p16xMNKKoiJCVZY5PW/AfILw2xe1LfruTcfAKBj3a+wgNYP5I9ZEKNDOItoRt53p4EiPV6iRSICy8EPanG9ZVA==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.0.tgz", - "integrity": "sha512-m19UQTRtxMzKAm8QxfKpvh6OwQSXaW1CdZPoCaQuLwAq7VZMNuhJmZR4g5281s2ECt658sldnJfdpSZZaxUGMQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.28.0", - "@typescript-eslint/visitor-keys": "4.28.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "dependencies": { - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.0.tgz", - "integrity": "sha512-PjJyTWwrlrvM5jazxYF5ZPs/nl0kHDZMVbuIcbpawVXaDPelp3+S9zpOz5RmVUfS/fD5l5+ZXNKnWhNYjPzCvw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.28.0", - "eslint-visitor-keys": "^2.0.0" - } - }, - "@wry/equality": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.1.11.tgz", - "integrity": "sha512-mwEVBDUVODlsQQ5dfuLUS5/Tf7jqUKyhKYHmVi4fPB6bDMOfWvUPJmKgS1Z7Za/sOI3vzWt4+O7yCiL/70MogA==", - "requires": { - "tslib": "^1.9.3" - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "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-align": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", - "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", - "dev": true, - "requires": { - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "apollo-cache-control": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.14.0.tgz", - "integrity": "sha512-qN4BCq90egQrgNnTRMUHikLZZAprf3gbm8rC5Vwmc6ZdLolQ7bFsa769Hqi6Tq/lS31KLsXBLTOsRbfPHph12w==", - "requires": { - "apollo-server-env": "^3.1.0", - "apollo-server-plugin-base": "^0.13.0" - } - }, - "apollo-datasource": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.9.0.tgz", - "integrity": "sha512-y8H99NExU1Sk4TvcaUxTdzfq2SZo6uSj5dyh75XSQvbpH6gdAXIW9MaBcvlNC7n0cVPsidHmOcHOWxJ/pTXGjA==", - "requires": { - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - } - }, - "apollo-graphql": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/apollo-graphql/-/apollo-graphql-0.9.3.tgz", - "integrity": "sha512-rcAl2E841Iko4kSzj4Pt3PRBitmyq1MvoEmpl04TQSpGnoVgl1E/ZXuLBYxMTSnEAm7umn2IsoY+c6Ll9U/10A==", - "requires": { - "core-js-pure": "^3.10.2", - "lodash.sortby": "^4.7.0", - "sha.js": "^2.4.11" - } - }, - "apollo-link": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.14.tgz", - "integrity": "sha512-p67CMEFP7kOG1JZ0ZkYZwRDa369w5PIjtMjvrQd/HnIV8FRsHRqLqK+oAZQnFa1DDdZtOtHTi+aMIW6EatC2jg==", - "requires": { - "apollo-utilities": "^1.3.0", - "ts-invariant": "^0.4.0", - "tslib": "^1.9.3", - "zen-observable-ts": "^0.8.21" - }, - "dependencies": { - "zen-observable-ts": { - "version": "0.8.21", - "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz", - "integrity": "sha512-Yj3yXweRc8LdRMrCC8nIc4kkjWecPAUVh0TI0OUrWXx6aX790vLcDlWca6I4vsyCGH3LpWxq0dJRcMOFoVqmeg==", - "requires": { - "tslib": "^1.9.3", - "zen-observable": "^0.8.0" - } - } - } - }, - "apollo-reporting-protobuf": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz", - "integrity": "sha512-B3XmnkH6Y458iV6OsA7AhfwvTgeZnFq9nPVjbxmLKnvfkEl8hYADtz724uPa0WeBiD7DSFcnLtqg9yGmCkBohg==", - "requires": { - "@apollo/protobufjs": "1.2.2" - } - }, - "apollo-server-caching": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.7.0.tgz", - "integrity": "sha512-MsVCuf/2FxuTFVhGLK13B+TZH9tBd2qkyoXKKILIiGcZ5CDUEBO14vIV63aNkMkS1xxvK2U4wBcuuNj/VH2Mkw==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "apollo-server-core": { - "version": "2.25.2", - "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.25.2.tgz", - "integrity": "sha512-lrohEjde2TmmDTO7FlOs8x5QQbAS0Sd3/t0TaK2TWaodfzi92QAvIsq321Mol6p6oEqmjm8POIDHW1EuJd7XMA==", - "requires": { - "@apollographql/apollo-tools": "^0.5.0", - "@apollographql/graphql-playground-html": "1.6.27", - "@apollographql/graphql-upload-8-fork": "^8.1.3", - "@josephg/resolvable": "^1.0.0", - "@types/ws": "^7.0.0", - "apollo-cache-control": "^0.14.0", - "apollo-datasource": "^0.9.0", - "apollo-graphql": "^0.9.0", - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0", - "apollo-server-errors": "^2.5.0", - "apollo-server-plugin-base": "^0.13.0", - "apollo-server-types": "^0.9.0", - "apollo-tracing": "^0.15.0", - "async-retry": "^1.2.1", - "fast-json-stable-stringify": "^2.0.0", - "graphql-extensions": "^0.15.0", - "graphql-tag": "^2.11.0", - "graphql-tools": "^4.0.8", - "loglevel": "^1.6.7", - "lru-cache": "^6.0.0", - "sha.js": "^2.4.11", - "subscriptions-transport-ws": "^0.9.19", - "uuid": "^8.0.0" - } - }, - "apollo-server-env": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-3.1.0.tgz", - "integrity": "sha512-iGdZgEOAuVop3vb0F2J3+kaBVi4caMoxefHosxmgzAbbSpvWehB8Y1QiSyyMeouYC38XNVk5wnZl+jdGSsWsIQ==", - "requires": { - "node-fetch": "^2.6.1", - "util.promisify": "^1.0.0" - } - }, - "apollo-server-errors": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.5.0.tgz", - "integrity": "sha512-lO5oTjgiC3vlVg2RKr3RiXIIQ5pGXBFxYGGUkKDhTud3jMIhs+gel8L8zsEjKaKxkjHhCQAA/bcEfYiKkGQIvA==" - }, - "apollo-server-express": { - "version": "2.25.2", - "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.25.2.tgz", - "integrity": "sha512-A2gF2e85vvDugPlajbhr0A14cDFDIGX0mteNOJ8P3Z3cIM0D4hwrWxJidI+SzobefDIyIHu1dynFedJVhV0euQ==", - "requires": { - "@apollographql/graphql-playground-html": "1.6.27", - "@types/accepts": "^1.3.5", - "@types/body-parser": "1.19.0", - "@types/cors": "2.8.10", - "@types/express": "^4.17.12", - "@types/express-serve-static-core": "^4.17.21", - "accepts": "^1.3.5", - "apollo-server-core": "^2.25.2", - "apollo-server-types": "^0.9.0", - "body-parser": "^1.18.3", - "cors": "^2.8.5", - "express": "^4.17.1", - "graphql-subscriptions": "^1.0.0", - "graphql-tools": "^4.0.8", - "parseurl": "^1.3.2", - "subscriptions-transport-ws": "^0.9.19", - "type-is": "^1.6.16" - }, - "dependencies": { - "@types/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.22", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.22.tgz", - "integrity": "sha512-WdqmrUsRS4ootGha6tVwk/IVHM1iorU8tGehftQD2NWiPniw/sm7xdJOIlXLwqdInL9wBw/p7oO8vaYEF3NDmA==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - } - } - }, - "apollo-server-plugin-base": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.13.0.tgz", - "integrity": "sha512-L3TMmq2YE6BU6I4Tmgygmd0W55L+6XfD9137k+cWEBFu50vRY4Re+d+fL5WuPkk5xSPKd/PIaqzidu5V/zz8Kg==", - "requires": { - "apollo-server-types": "^0.9.0" - } - }, - "apollo-server-types": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/apollo-server-types/-/apollo-server-types-0.9.0.tgz", - "integrity": "sha512-qk9tg4Imwpk732JJHBkhW0jzfG0nFsLqK2DY6UhvJf7jLnRePYsPxWfPiNkxni27pLE2tiNlCwoDFSeWqpZyBg==", - "requires": { - "apollo-reporting-protobuf": "^0.8.0", - "apollo-server-caching": "^0.7.0", - "apollo-server-env": "^3.1.0" - } - }, - "apollo-tracing": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.15.0.tgz", - "integrity": "sha512-UP0fztFvaZPHDhIB/J+qGuy6hWO4If069MGC98qVs0I8FICIGu4/8ykpX3X3K6RtaQ56EDAWKykCxFv4ScxMeA==", - "requires": { - "apollo-server-env": "^3.1.0", - "apollo-server-plugin-base": "^0.13.0" - } - }, - "apollo-utilities": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.3.4.tgz", - "integrity": "sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig==", - "requires": { - "@wry/equality": "^0.1.2", - "fast-json-stable-stringify": "^2.0.0", - "ts-invariant": "^0.4.0", - "tslib": "^1.10.0" - } - }, - "app-root-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", - "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==" - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - } - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "async-retry": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz", - "integrity": "sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==", - "requires": { - "retry": "0.12.0" - } - }, - "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", - "requires": { - "follow-redirects": "^1.10.0" - } - }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "dependencies": { - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - } - } - }, - "boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" - }, - "dependencies": { - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "busboy": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz", - "integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==", - "requires": { - "dicer": "0.3.0" - } - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.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" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "class-validator": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.13.1.tgz", - "integrity": "sha512-zWIeYFhUitvAHBwNhDdCRK09hWx+P0HUwFE8US8/CxFpMVzkUK8RJl7yOIE+BVu2lxyPNgeOaFv78tLE47jBIg==", - "requires": { - "@types/validator": "^13.1.3", - "libphonenumber-js": "^1.9.7", - "validator": "^13.5.2" - } - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, - "cli-highlight": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", - "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", - "requires": { - "chalk": "^4.0.0", - "highlight.js": "^10.7.1", - "mz": "^2.4.0", - "parse5": "^5.1.1", - "parse5-htmlparser2-tree-adapter": "^6.0.0", - "yargs": "^16.0.0" - }, - "dependencies": { - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - } - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "core-js-pure": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.16.0.tgz", - "integrity": "sha512-wzlhZNepF/QA9yvx3ePDgNGudU5KDB8lu/TRPKelYA/QtSnkS/cLl2W+TIdEX1FAFcBr0YpY7tPDlcmXJ7AyiQ==" - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, - "cssfilter": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", - "integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "deprecated-decorator": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz", - "integrity": "sha1-AJZjF7ehL+kvPMgx91g68ym4bDc=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "dicer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", - "integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==", - "requires": { - "streamsearch": "0.1.2" - } - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - }, - "dependencies": { - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - } - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.18.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz", - "integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.29.0.tgz", - "integrity": "sha512-82G/JToB9qIy/ArBzIWG9xvvwL3R86AlCjtGw+A29OMZDqhTybz/MByORSukGxeI+YPCR4coYyITKk8BFH9nDA==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true - }, - "eslint-config-standard": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", - "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", - "dev": true - }, - "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - } - }, - "eslint-module-utils": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", - "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-es": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, - "requires": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - } - }, - "eslint-plugin-import": { - "version": "2.23.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", - "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", - "dev": true, - "requires": { - "array-includes": "^3.1.3", - "array.prototype.flat": "^1.2.4", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.4", - "eslint-module-utils": "^2.6.1", - "find-up": "^2.0.0", - "has": "^1.0.3", - "is-core-module": "^2.4.0", - "minimatch": "^3.0.4", - "object.values": "^1.1.3", - "pkg-up": "^2.0.0", - "read-pkg-up": "^3.0.0", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.9.0" - } - }, - "eslint-plugin-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "requires": { - "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" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - } - } - }, - "eslint-plugin-prettier": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", - "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-plugin-promise": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz", - "integrity": "sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng==", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "dependencies": { - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - } - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "eventemitter3": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - } - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "requires": { - "@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": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.1.tgz", - "integrity": "sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "figlet": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/figlet/-/figlet-1.5.2.tgz", - "integrity": "sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==" - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "follow-redirects": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", - "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-capacitor": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-2.0.4.tgz", - "integrity": "sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "requires": { - "is-property": "^1.0.2" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", - "dev": true, - "requires": { - "ini": "1.3.7" - } - }, - "globals": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", - "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - } - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "graphql": { - "version": "15.5.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.5.1.tgz", - "integrity": "sha512-FeTRX67T3LoE3LWAxxOlW2K3Bz+rMYAC18rRguK4wgXaTZMiJwSUwDmPFo3UadAKbzirKIg5Qy+sNJXbpPRnQw==" - }, - "graphql-extensions": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.15.0.tgz", - "integrity": "sha512-bVddVO8YFJPwuACn+3pgmrEg6I8iBuYLuwvxiE+lcQQ7POotVZxm2rgGw0PvVYmWWf3DT7nTVDZ5ROh/ALp8mA==", - "requires": { - "@apollographql/apollo-tools": "^0.5.0", - "apollo-server-env": "^3.1.0", - "apollo-server-types": "^0.9.0" - } - }, - "graphql-query-complexity": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/graphql-query-complexity/-/graphql-query-complexity-0.7.2.tgz", - "integrity": "sha512-+VgmrfxGEjHI3zuojWOR8bsz7Ycz/BZjNjxnlUieTz5DsB92WoIrYCSZdWG7UWZ3rfcA1Gb2Nf+wB80GsaZWuQ==", - "requires": { - "lodash.get": "^4.4.2" - } - }, - "graphql-subscriptions": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz", - "integrity": "sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g==", - "requires": { - "iterall": "^1.3.0" - } - }, - "graphql-tag": { - "version": "2.12.5", - "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.5.tgz", - "integrity": "sha512-5xNhP4063d16Pz3HBtKprutsPrmHZi5IdUGOWRxA2B6VF7BIRGOHZ5WQvDmJXZuPcBg7rYwaFxvQYjqkSdR3TQ==", - "requires": { - "tslib": "^2.1.0" - }, - "dependencies": { - "tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" - } - } - }, - "graphql-tools": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-4.0.8.tgz", - "integrity": "sha512-MW+ioleBrwhRjalKjYaLQbr+920pHBgy9vM/n47sswtns8+96sRn5M/G+J1eu7IMeKWiN/9p6tmwCHU7552VJg==", - "requires": { - "apollo-link": "^1.2.14", - "apollo-utilities": "^1.0.1", - "deprecated-decorator": "^0.1.6", - "iterall": "^1.1.3", - "uuid": "^3.1.0" - }, - "dependencies": { - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - } - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true - }, - "highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==" - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "http-errors": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", - "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", - "dev": true - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==" - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", - "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", - "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", - "dev": true, - "requires": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" - } - }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" - }, - "is-npm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", - "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==" - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, - "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - } - }, - "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "iterall": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", - "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "requires": { - "package-json": "^6.3.0" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "libphonenumber-js": { - "version": "1.9.22", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.22.tgz", - "integrity": "sha512-nE0aF0wrNq09ewF36s9FVqRW73hmpw6cobVDlbexmsu1432LEfuN24BCudNuRx4t2rElSeK/N0JbedzRW/TC4A==" - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "loglevel": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", - "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", - "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" - }, - "mime-types": { - "version": "2.1.32", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", - "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", - "requires": { - "mime-db": "1.49.0" - } - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "mysql2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.0.tgz", - "integrity": "sha512-0t5Ivps5Tdy5YHk5NdKwQhe/4Qyn2pload+S+UooDBvsqngtzujG1BaTWBihQLfeKO3t3122/GtusBtmHEHqww==", - "requires": { - "denque": "^1.4.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.6.2", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "requires": { - "lru-cache": "^4.1.3" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, - "nodemon": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", - "integrity": "sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==", - "dev": true, - "requires": { - "chokidar": "^3.2.2", - "debug": "^3.2.6", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.3", - "update-notifier": "^4.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object-path": { - "version": "0.11.5", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.5.tgz", - "integrity": "sha512-jgSbThcoR/s+XumvGMTMf81QVBmah+/Q7K7YduKeKVWL7N111unR2d6pZZarSk6kY/caeNxUDyxOvMWyzoU2eg==" - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", - "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" - } - }, - "object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "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" - } - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parent-require": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz", - "integrity": "sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc=" - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" - }, - "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "requires": { - "parse5": "^6.0.1" - }, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - } - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, - "prettier": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", - "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "requires": { - "escape-goat": "^2.0.0" - } - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - } - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - } - } - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", - "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^3.0.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - } - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "requires": { - "semver": "^6.3.0" - } - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - } - } - }, - "seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", - "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==" - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - } - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" - } - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "subscriptions-transport-ws": { - "version": "0.9.19", - "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz", - "integrity": "sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw==", - "requires": { - "backo2": "^1.0.2", - "eventemitter3": "^3.1.0", - "iterall": "^1.2.1", - "symbol-observable": "^1.0.4", - "ws": "^5.2.0 || ^6.0.0 || ^7.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" - }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.2.tgz", - "integrity": "sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "term-size": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", - "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", - "dev": true - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "requires": { - "nopt": "~1.0.10" - } - }, - "ts-invariant": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz", - "integrity": "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==", - "requires": { - "tslib": "^1.9.3" - } - }, - "ts-node": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.0.0.tgz", - "integrity": "sha512-ROWeOIUvfFbPZkoDis0L/55Fk+6gFQNZwwKPLinacRl6tsxstTF1DbAcLKkovwnpKMVvOMHP1TIbnwXwtLg1gg==", - "dev": true, - "requires": { - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - } - }, - "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", - "strip-bom": "^3.0.0" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "type-graphql": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/type-graphql/-/type-graphql-1.1.1.tgz", - "integrity": "sha512-iOOWVn0ehCYMukmnXStbkRwFE9dcjt7/oDcBS1JyQZo9CbhlIll4lHHps54HMEk4A4c8bUPd+DjK8w1/ZrxB4A==", - "requires": { - "@types/glob": "^7.1.3", - "@types/node": "*", - "@types/semver": "^7.3.3", - "glob": "^7.1.6", - "graphql-query-complexity": "^0.7.0", - "graphql-subscriptions": "^1.1.0", - "semver": "^7.3.2", - "tslib": "^2.0.1" - }, - "dependencies": { - "@types/node": { - "version": "14.17.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.4.tgz", - "integrity": "sha512-8kQ3+wKGRNN0ghtEn7EGps/B8CzuBz1nXZEIGGLP2GnwbqYn4dbTs7k+VKLTq1HvZLRCIDtN3Snx1Ege8B7L5A==" - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" - } - } - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typeorm": { - "version": "0.2.37", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.2.37.tgz", - "integrity": "sha512-7rkW0yCgFC24I5T0f3S/twmLSuccPh1SQmxET/oDWn2sSDVzbyWdnItSdKy27CdJGTlKHYtUVeOcMYw5LRsXVw==", - "requires": { - "@sqltools/formatter": "^1.2.2", - "app-root-path": "^3.0.0", - "buffer": "^6.0.3", - "chalk": "^4.1.0", - "cli-highlight": "^2.1.11", - "debug": "^4.3.1", - "dotenv": "^8.2.0", - "glob": "^7.1.6", - "js-yaml": "^4.0.0", - "mkdirp": "^1.0.4", - "reflect-metadata": "^0.1.13", - "sha.js": "^2.4.11", - "tslib": "^2.1.0", - "xml2js": "^0.4.23", - "yargonaut": "^1.1.4", - "yargs": "^17.0.1", - "zen-observable-ts": "^1.0.0" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "requires": { - "ms": "2.1.2" - } - }, - "dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { - "argparse": "^2.0.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - } - } - }, - "typescript": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.4.tgz", - "integrity": "sha512-uauPG7XZn9F/mo+7MrsRjyvbxFpzemRjKEZXS4AK83oP2KKOJPvb+9cO/gmnv8arWZvhnjVOXz7B49m1l0e9Ew==", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "undefsafe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", - "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", - "dev": true, - "requires": { - "debug": "^2.2.0" - } - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "update-notifier": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", - "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", - "dev": true, - "requires": { - "boxen": "^4.2.0", - "chalk": "^3.0.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.1", - "is-npm": "^4.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.0.0", - "pupa": "^2.0.1", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } - }, - "util.promisify": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.1.1.tgz", - "integrity": "sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "for-each": "^0.3.3", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.1" - } - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "validator": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", - "integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "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" - } - }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "requires": { - "string-width": "^4.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", - "integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==" - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - }, - "xss": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.9.tgz", - "integrity": "sha512-2t7FahYnGJys6DpHLhajusId7R0Pm2yTmuL0GV9+mV0ZlaLSnb2toBmppATfg5sWIhZQGlsTLoecSzya+l4EAQ==", - "requires": { - "commander": "^2.20.3", - "cssfilter": "0.0.10" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yargonaut": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/yargonaut/-/yargonaut-1.1.4.tgz", - "integrity": "sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==", - "requires": { - "chalk": "^1.1.1", - "figlet": "^1.1.1", - "parent-require": "^1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "yargs": { - "version": "17.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.2.0.tgz", - "integrity": "sha512-UPeZv4h9Xv510ibpt5rdsUNzgD78nMa1rhxxCgvkKiq06hlKCEHJLiJ6Ub8zDg/wR6hedEI6ovnd2vCvJ4nusA==", - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "zen-observable": { - "version": "0.8.15", - "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", - "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==" - }, - "zen-observable-ts": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz", - "integrity": "sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==", - "requires": { - "@types/zen-observable": "0.8.3", - "zen-observable": "0.8.15" - } - } - } -} diff --git a/backend/src/graphql/models/Decay.ts b/backend/src/graphql/models/Decay.ts index 9bc89f6ec..17ee8fbac 100644 --- a/backend/src/graphql/models/Decay.ts +++ b/backend/src/graphql/models/Decay.ts @@ -25,17 +25,19 @@ export class Decay { @Field(() => Number) balance: number + // timestamp in seconds @Field(() => Int, { nullable: true }) - decayStart: number + decayStart: string + // timestamp in seconds @Field(() => Int, { nullable: true }) - decayEnd: number + decayEnd: string @Field(() => String, { nullable: true }) decayDuration?: number @Field(() => Int, { nullable: true }) - decayStartBlock?: number + decayStartBlock?: string static decayStartBlockTransaction: Transaction | undefined } diff --git a/backend/src/graphql/models/Transaction.ts b/backend/src/graphql/models/Transaction.ts index c34cac1c5..69956cf9b 100644 --- a/backend/src/graphql/models/Transaction.ts +++ b/backend/src/graphql/models/Transaction.ts @@ -10,22 +10,11 @@ import { Decay } from './Decay' @ObjectType() export class Transaction { - constructor() - constructor(json: any) - constructor(json?: any) { - if (json) { - this.type = json.type - this.balance = Number(json.balance) - this.decayStart = json.decay_start - this.decayEnd = json.decay_end - - this.memo = json.memo - this.transactionId = json.transaction_id - this.name = json.name - this.email = json.email - this.date = json.date - this.decay = json.decay ? new Decay(json.decay) : undefined - } + constructor() { + this.type = '' + this.balance = 0 + this.totalBalance = 0 + this.memo = '' } @Field(() => String) @@ -38,10 +27,10 @@ export class Transaction { totalBalance: number @Field({ nullable: true }) - decayStart?: number + decayStart?: string @Field({ nullable: true }) - decayEnd?: number + decayEnd?: string @Field({ nullable: true }) decayDuration?: number @@ -67,15 +56,12 @@ export class Transaction { @ObjectType() export class TransactionList { - constructor(json: any) { - this.gdtSum = Number(json.gdtSum) - this.count = json.count - this.balance = Number(json.balance) - this.decay = Number(json.decay) - this.decayDate = json.decay_date - this.transactions = json.transactions.map((el: any) => { - return new Transaction(el) - }) + constructor() { + this.gdtSum = 0 + this.count = 0 + this.balance = 0 + this.decay = 0 + this.decayDate = '' } @Field(() => Number) diff --git a/backend/src/graphql/resolvers/TransactionResolver.ts b/backend/src/graphql/resolvers/TransactionResolver.ts index 3762cccee..31aac8e04 100644 --- a/backend/src/graphql/resolvers/TransactionResolver.ts +++ b/backend/src/graphql/resolvers/TransactionResolver.ts @@ -46,7 +46,6 @@ export class TransactionResolver { ) transactions.decayDate = now.toString() } - return transactions } diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts index 8c4519776..596ccd03e 100644 --- a/backend/src/graphql/resolvers/listTransactions.ts +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -73,7 +73,9 @@ async function calculateAndAddDecayTransactions( prev.transactionId < decayStartTransaction.id && current.transactionId > decayStartTransaction.id ) { - finalTransaction.decay.decayStartBlock = decayStartTransaction.received.getTime() + finalTransaction.decay.decayStartBlock = ( + decayStartTransaction.received.getTime() / 1000 + ).toString() } } } @@ -181,14 +183,8 @@ export default async function listTransactions( } } - const transactionList = new TransactionList({ - gdtSum: 0, - count: userTransactionsCount, - balance: 0, - decay: 0, - decay_date: '', - transactions: transactions, - }) - + const transactionList = new TransactionList() + transactionList.count = userTransactionsCount + transactionList.transactions = transactions return transactionList } diff --git a/backend/src/typeorm/entity/UserTransaction.ts b/backend/src/typeorm/entity/UserTransaction.ts index 1f32dc454..2f5bd69fc 100644 --- a/backend/src/typeorm/entity/UserTransaction.ts +++ b/backend/src/typeorm/entity/UserTransaction.ts @@ -18,7 +18,7 @@ export class UserTransaction extends BaseEntity { balance: number @Column({ name: 'balance_date', type: 'timestamp' }) - balanceDate: number + balanceDate: Date static findByUserPaged( userId: number, diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index 1d92e8cec..a7c670cc5 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -17,29 +17,31 @@ async function calculateDecay(amount: number, from: Date, to: Date): Promise { const decayStartBlock = await Decay.getDecayStartBlock() const result = new Decay(undefined) result.balance = amount - result.decayStart = from - result.decayEnd = from + const fromMillis = typeof from === 'number' ? from : from.getTime() + const toMillis = typeof to === 'number' ? to : to.getTime() + result.decayStart = (fromMillis / 1000).toString() + result.decayEnd = (toMillis / 1000).toString() // (amount, from.getTime(), to.getTime()) // if no decay start block exist or decay startet after end date - if (decayStartBlock === undefined || decayStartBlock.received.getTime() > to) { + if (decayStartBlock === undefined || decayStartBlock.received.getTime() > toMillis) { return result } // if decay start date is before start date we calculate decay for full duration - if (decayStartBlock.received.getTime() < from) { - result.decayDuration = to - from + if (decayStartBlock.received.getTime() < fromMillis) { + result.decayDuration = toMillis - fromMillis } // if decay start in between start date and end date we caculcate decay from decay start time to end date else { - result.decayDuration = to - decayStartBlock.received.getTime() + result.decayDuration = toMillis - decayStartBlock.received.getTime() } // js use timestamp in milliseconds but we calculate with seconds result.decayDuration /= 1000 From bf8bd24abf4f59d4ae0562dd180e4e75472b4ad2 Mon Sep 17 00:00:00 2001 From: einhorn_b Date: Wed, 29 Sep 2021 14:37:26 +0200 Subject: [PATCH 36/37] fixed decay and missing user data bugs --- .../graphql/resolvers/TransactionResolver.ts | 1 + .../src/graphql/resolvers/listTransactions.ts | 20 +++++++++++-------- backend/src/typeorm/entity/User.ts | 4 ++-- backend/src/util/decay.ts | 7 +++++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/backend/src/graphql/resolvers/TransactionResolver.ts b/backend/src/graphql/resolvers/TransactionResolver.ts index 31aac8e04..3762cccee 100644 --- a/backend/src/graphql/resolvers/TransactionResolver.ts +++ b/backend/src/graphql/resolvers/TransactionResolver.ts @@ -46,6 +46,7 @@ export class TransactionResolver { ) transactions.decayDate = now.toString() } + return transactions } diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts index 596ccd03e..1de7d7dcc 100644 --- a/backend/src/graphql/resolvers/listTransactions.ts +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -18,12 +18,7 @@ async function calculateAndAddDecayTransactions( userTransactions.forEach((userTransaction: dbUserTransaction) => { transactionIds.push(userTransaction.transactionId) - involvedUserIds.push(userTransaction.userId) }) - // remove duplicates - // https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates - const involvedUsersUnique = involvedUserIds.filter((v, i, a) => a.indexOf(v) === i) - const userIndiced = await dbUser.getUsersIndiced(involvedUsersUnique) const transactions = await dbTransaction .createQueryBuilder('transaction') @@ -43,15 +38,24 @@ async function calculateAndAddDecayTransactions( const transactionIndiced: dbTransaction[] = [] transactions.forEach((transaction: dbTransaction) => { transactionIndiced[transaction.id] = transaction + if (transaction.transactionTypeId === 2) { + involvedUserIds.push(transaction.transactionSendCoin.userId) + involvedUserIds.push(transaction.transactionSendCoin.recipiantUserId) + } }) + // remove duplicates + // https://stackoverflow.com/questions/1960473/get-all-unique-values-in-a-javascript-array-remove-duplicates + const involvedUsersUnique = involvedUserIds.filter((v, i, a) => a.indexOf(v) === i) + const userIndiced = await dbUser.getUsersIndiced(involvedUsersUnique) const decayStartTransaction = await Decay.getDecayStartBlock() - await userTransactions.forEach(async (userTransaction: dbUserTransaction, i: number) => { + for (let i = 0; i < userTransactions.length; i++) { + const userTransaction = userTransactions[i] const transaction = transactionIndiced[userTransaction.transactionId] const finalTransaction = new Transaction() finalTransaction.transactionId = transaction.id - finalTransaction.date = transaction.received.toString() + finalTransaction.date = transaction.received.toISOString() finalTransaction.memo = transaction.memo finalTransaction.totalBalance = roundFloorFrom4(userTransaction.balance) const prev = i > 0 ? userTransactions[i - 1] : null @@ -137,7 +141,7 @@ async function calculateAndAddDecayTransactions( finalTransactions.push(decayTransaction) } } - }) + } return finalTransactions } diff --git a/backend/src/typeorm/entity/User.ts b/backend/src/typeorm/entity/User.ts index e82ba5deb..1cd5b1c4c 100644 --- a/backend/src/typeorm/entity/User.ts +++ b/backend/src/typeorm/entity/User.ts @@ -39,8 +39,8 @@ export class User extends BaseEntity { .where('user.id IN (:...users)', { users: userIds }) .getMany() const usersIndiced: User[] = [] - users.forEach((value, index) => { - usersIndiced[index] = value + users.forEach((value) => { + usersIndiced[value.id] = value }) return usersIndiced } diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index a7c670cc5..dfeca7351 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -21,6 +21,7 @@ async function calculateDecayWithInterval( to: number | Date, ): Promise { const decayStartBlock = await Decay.getDecayStartBlock() + const result = new Decay(undefined) result.balance = amount const fromMillis = typeof from === 'number' ? from : from.getTime() @@ -34,14 +35,16 @@ async function calculateDecayWithInterval( if (decayStartBlock === undefined || decayStartBlock.received.getTime() > toMillis) { return result } + const decayStartBlockMillis = decayStartBlock.received.getTime() // if decay start date is before start date we calculate decay for full duration - if (decayStartBlock.received.getTime() < fromMillis) { + if (decayStartBlockMillis < fromMillis) { result.decayDuration = toMillis - fromMillis } // if decay start in between start date and end date we caculcate decay from decay start time to end date else { - result.decayDuration = toMillis - decayStartBlock.received.getTime() + result.decayDuration = toMillis - decayStartBlockMillis + result.decayStart = (decayStartBlockMillis / 1000).toString() } // js use timestamp in milliseconds but we calculate with seconds result.decayDuration /= 1000 From d4d19b78011f02c5ed9dfa0080fa8b8852d5a9a5 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 30 Sep 2021 18:52:12 +0200 Subject: [PATCH 37/37] Update backend/src/util/decay.ts Co-authored-by: Ulf Gebhardt --- backend/src/util/decay.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index dfeca7351..3d39b198f 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -32,7 +32,7 @@ async function calculateDecayWithInterval( // (amount, from.getTime(), to.getTime()) // if no decay start block exist or decay startet after end date - if (decayStartBlock === undefined || decayStartBlock.received.getTime() > toMillis) { + if (!decayStartBlock || decayStartBlock.received.getTime() > toMillis) { return result } const decayStartBlockMillis = decayStartBlock.received.getTime()