Merge branch '3030-feature-role-administration-backend' of github.com:gradido/gradido into 3030-feature-role-administration-backend

This commit is contained in:
Moriz Wahl 2023-07-18 13:43:10 +02:00
commit 802b7cc3dc
35 changed files with 685 additions and 287 deletions

View File

@ -6,17 +6,14 @@ import { MODERATOR_RIGHTS } from './MODERATOR_RIGHTS'
import { Role } from './Role'
import { USER_RIGHTS } from './USER_RIGHTS'
export const ROLE_UNAUTHORIZED = new Role(RoleNames.ROLE_NAME_UNAUTHORIZED, INALIENABLE_RIGHTS)
export const ROLE_USER = new Role(RoleNames.ROLE_NAME_USER, [
...INALIENABLE_RIGHTS,
...USER_RIGHTS,
])
export const ROLE_MODERATOR = new Role(RoleNames.ROLE_NAME_MODERATOR, [
export const ROLE_UNAUTHORIZED = new Role(RoleNames.MODERATOR, INALIENABLE_RIGHTS)
export const ROLE_USER = new Role(RoleNames.USER, [...INALIENABLE_RIGHTS, ...USER_RIGHTS])
export const ROLE_MODERATOR = new Role(RoleNames.MODERATOR, [
...INALIENABLE_RIGHTS,
...USER_RIGHTS,
...MODERATOR_RIGHTS,
])
export const ROLE_ADMIN = new Role(RoleNames.ROLE_NAME_ADMIN, [
export const ROLE_ADMIN = new Role(RoleNames.ADMIN, [
...INALIENABLE_RIGHTS,
...USER_RIGHTS,
...MODERATOR_RIGHTS,

View File

@ -8,6 +8,6 @@ export class SetUserRoleArgs {
@Field(() => Int)
userId: number
@Field(() => RoleNames, { nullable: true } )
role: RoleNames | null
@Field(() => RoleNames, { nullable: true })
role: RoleNames | null | undefined
}

View File

@ -1,13 +1,14 @@
import { User } from '@entity/User'
import { AuthChecker } from 'type-graphql'
import { RoleNames } from '@enum/RoleNames'
import { INALIENABLE_RIGHTS } from '@/auth/INALIENABLE_RIGHTS'
import { decode, encode } from '@/auth/JWT'
import { RIGHTS } from '@/auth/RIGHTS'
import { ROLE_UNAUTHORIZED, ROLE_USER, ROLE_ADMIN, ROLE_MODERATOR } from '@/auth/ROLES'
import { Context } from '@/server/context'
import { LogError } from '@/server/LogError'
import { RoleNames } from '@enum/RoleNames'
export const isAuthorized: AuthChecker<Context> = async ({ context }, rights) => {
context.role = ROLE_UNAUTHORIZED // unauthorized user
@ -41,10 +42,10 @@ export const isAuthorized: AuthChecker<Context> = async ({ context }, rights) =>
context.role = ROLE_USER
if (user.userRoles?.length > 0) {
switch (user.userRoles[0].role) {
case RoleNames.ROLE_NAME_ADMIN:
case RoleNames.ADMIN:
context.role = ROLE_ADMIN
break
case RoleNames.ROLE_NAME_MODERATOR:
case RoleNames.MODERATOR:
context.role = ROLE_MODERATOR
break
default:

View File

@ -1,10 +1,10 @@
import { registerEnumType } from 'type-graphql'
export enum RoleNames {
ROLE_NAME_ADMIN = 'admin',
ROLE_NAME_UNAUTHORIZED = 'unauthorized',
ROLE_NAME_USER = 'user',
ROLE_NAME_MODERATOR = 'moderator',
UNAUTHORIZED = 'UNAUTHORIZED',
USER = 'USER',
MODERATOR = 'MODERATOR',
ADMIN = 'ADMIN',
}
registerEnumType(RoleNames, {

View File

@ -1,56 +0,0 @@
import { UserContact as dbUserContact } from '@entity/UserContact'
import { ObjectType, Field, Int } from 'type-graphql'
@ObjectType()
export class UserContact {
constructor(userContact: dbUserContact) {
this.id = userContact.id
this.type = userContact.type
this.userId = userContact.userId
this.email = userContact.email
// this.emailVerificationCode = userContact.emailVerificationCode
this.emailOptInTypeId = userContact.emailOptInTypeId
this.emailResendCount = userContact.emailResendCount
this.emailChecked = userContact.emailChecked
this.phone = userContact.phone
this.createdAt = userContact.createdAt
this.updatedAt = userContact.updatedAt
this.deletedAt = userContact.deletedAt
}
@Field(() => Int)
id: number
@Field(() => String)
type: string
@Field(() => Int)
userId: number
@Field(() => String)
email: string
// @Field(() => BigInt, { nullable: true })
// emailVerificationCode: BigInt | null
@Field(() => Int, { nullable: true })
emailOptInTypeId: number | null
@Field(() => Int, { nullable: true })
emailResendCount: number | null
@Field(() => Boolean)
emailChecked: boolean
@Field(() => String, { nullable: true })
phone: string | null
@Field(() => Date)
createdAt: Date
@Field(() => Date, { nullable: true })
updatedAt: Date | null
@Field(() => Date, { nullable: true })
deletedAt: Date | null
}

View File

@ -10,19 +10,20 @@ import { TransactionLink } from '@entity/TransactionLink'
import { User } from '@entity/User'
import { UserContact } from '@entity/UserContact'
import { UserRole } from '@entity/UserRole'
import { UserInputError } from 'apollo-server-express'
import { ApolloServerTestClient } from 'apollo-server-testing'
import { GraphQLError } from 'graphql'
import { v4 as uuidv4, validate as validateUUID, version as versionUUID } from 'uuid'
import { OptInType } from '@enum/OptInType'
import { PasswordEncryptionType } from '@enum/PasswordEncryptionType'
import { RoleNames } from '@enum/RoleNames'
import { UserContactType } from '@enum/UserContactType'
import { ContributionLink } from '@model/ContributionLink'
import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers'
import { logger, i18n as localization } from '@test/testSetup'
import { subscribe } from '@/apis/KlicktippController'
import { RoleNames } from '@enum/RoleNames'
import { CONFIG } from '@/config'
import {
sendAccountActivationEmail,
@ -345,7 +346,7 @@ describe('UserResolver', () => {
peter.userRoles = [] as UserRole[]
peter.userRoles[0] = UserRole.create()
peter.userRoles[0].createdAt = new Date()
peter.userRoles[0].role = RoleNames.ROLE_NAME_ADMIN
peter.userRoles[0].role = RoleNames.ADMIN
peter.userRoles[0].userId = peter.id
await peter.userRoles[0].save()
@ -1411,7 +1412,7 @@ describe('UserResolver', () => {
expect.objectContaining({
firstName: 'Peter',
lastName: 'Lustig',
role: RoleNames.ROLE_NAME_ADMIN,
role: RoleNames.ADMIN,
}),
]),
},
@ -1520,7 +1521,7 @@ describe('UserResolver', () => {
await expect(
mutate({
mutation: setUserRole,
variables: { userId: 1, role: RoleNames.ROLE_NAME_ADMIN },
variables: { userId: 1, role: RoleNames.ADMIN },
}),
).resolves.toEqual(
expect.objectContaining({
@ -1549,7 +1550,7 @@ describe('UserResolver', () => {
await expect(
mutate({
mutation: setUserRole,
variables: { userId: user.id + 1, role: RoleNames.ROLE_NAME_ADMIN },
variables: { userId: user.id + 1, role: RoleNames.ADMIN },
}),
).resolves.toEqual(
expect.objectContaining({
@ -1566,7 +1567,7 @@ describe('UserResolver', () => {
// set Moderator-Role for Peter
const userRole = await UserRole.findOneOrFail({ where: { userId: admin.id } })
userRole.role = RoleNames.ROLE_NAME_MODERATOR
userRole.role = RoleNames.MODERATOR
userRole.userId = admin.id
await UserRole.save(userRole)
@ -1585,7 +1586,7 @@ describe('UserResolver', () => {
await expect(
mutate({
mutation: setUserRole,
variables: { userId: user.id, role: RoleNames.ROLE_NAME_ADMIN },
variables: { userId: user.id, role: RoleNames.ADMIN },
}),
).resolves.toEqual(
expect.objectContaining({
@ -1613,12 +1614,12 @@ describe('UserResolver', () => {
it('returns user with new moderator-role', async () => {
const result = await mutate({
mutation: setUserRole,
variables: { userId: user.id, role: RoleNames.ROLE_NAME_MODERATOR },
variables: { userId: user.id, role: RoleNames.MODERATOR },
})
expect(result).toEqual(
expect.objectContaining({
data: {
setUserRole: RoleNames.ROLE_NAME_MODERATOR,
setUserRole: RoleNames.MODERATOR,
},
}),
)
@ -1635,7 +1636,7 @@ describe('UserResolver', () => {
await expect(
mutate({
mutation: setUserRole,
variables: { userId: admin.id + 1, role: RoleNames.ROLE_NAME_ADMIN },
variables: { userId: admin.id + 1, role: RoleNames.ADMIN },
}),
).resolves.toEqual(
expect.objectContaining({
@ -1669,31 +1670,23 @@ describe('UserResolver', () => {
it('returns admin-rolename', async () => {
const result = await mutate({
mutation: setUserRole,
variables: { userId: user.id, role: RoleNames.ROLE_NAME_ADMIN },
variables: { userId: user.id, role: RoleNames.ADMIN },
})
expect(result).toEqual(
expect.objectContaining({
data: {
setUserRole: RoleNames.ROLE_NAME_ADMIN,
setUserRole: RoleNames.ADMIN,
},
}),
)
})
it('stores the ADMIN_USER_ROLE_SET event in the database', async () => {
const userContact = await UserContact.findOneOrFail({
where: { email: 'bibi@bloxberg.de' },
relations: ['user'],
})
const adminContact = await UserContact.findOneOrFail({
where: { email: 'peter@lustig.de' },
relations: ['user'],
})
await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({
type: EventType.ADMIN_USER_ROLE_SET,
affectedUserId: userContact.user.id,
actingUserId: adminContact.user.id,
affectedUserId: user.id,
actingUserId: admin.id,
}),
)
})
@ -1703,12 +1696,12 @@ describe('UserResolver', () => {
it('returns date string', async () => {
const result = await mutate({
mutation: setUserRole,
variables: { userId: user.id, role: RoleNames.ROLE_NAME_MODERATOR },
variables: { userId: user.id, role: RoleNames.MODERATOR },
})
expect(result).toEqual(
expect.objectContaining({
data: {
setUserRole: RoleNames.ROLE_NAME_MODERATOR,
setUserRole: RoleNames.MODERATOR,
},
}),
)
@ -1716,19 +1709,11 @@ describe('UserResolver', () => {
})
it('stores the ADMIN_USER_ROLE_SET event in the database', async () => {
const userContact = await UserContact.findOneOrFail({
where: { email: 'bibi@bloxberg.de' },
relations: ['user'],
})
const adminContact = await UserContact.findOneOrFail({
where: { email: 'peter@lustig.de' },
relations: ['user'],
})
await expect(DbEvent.find()).resolves.toContainEqual(
expect.objectContaining({
type: EventType.ADMIN_USER_ROLE_SET,
affectedUserId: userContact.user.id,
actingUserId: adminContact.user.id,
affectedUserId: user.id,
actingUserId: admin.id,
}),
)
})
@ -1791,17 +1776,14 @@ describe('UserResolver', () => {
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('Not allowed to set user role=')],
errors: [
new UserInputError(
'Variable "$role" got invalid value "unknown rolename"; Value "unknown rolename" does not exist in "RoleNames" enum.',
),
],
}),
)
})
it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith(
'Not allowed to set user role=',
'unknown rolename',
)
})
})
describe('user has already role to be set', () => {
@ -1810,12 +1792,12 @@ describe('UserResolver', () => {
jest.clearAllMocks()
await mutate({
mutation: setUserRole,
variables: { userId: user.id, role: RoleNames.ROLE_NAME_ADMIN },
variables: { userId: user.id, role: RoleNames.ADMIN },
})
await expect(
mutate({
mutation: setUserRole,
variables: { userId: user.id, role: RoleNames.ROLE_NAME_ADMIN },
variables: { userId: user.id, role: RoleNames.ADMIN },
}),
).resolves.toEqual(
expect.objectContaining({
@ -1825,10 +1807,7 @@ describe('UserResolver', () => {
})
it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith(
'User already has role=',
RoleNames.ROLE_NAME_ADMIN,
)
expect(logger.error).toBeCalledWith('User already has role=', RoleNames.ADMIN)
})
})
@ -1837,12 +1816,12 @@ describe('UserResolver', () => {
jest.clearAllMocks()
await mutate({
mutation: setUserRole,
variables: { userId: user.id, role: RoleNames.ROLE_NAME_MODERATOR },
variables: { userId: user.id, role: RoleNames.MODERATOR },
})
await expect(
mutate({
mutation: setUserRole,
variables: { userId: user.id, role: RoleNames.ROLE_NAME_MODERATOR },
variables: { userId: user.id, role: RoleNames.MODERATOR },
}),
).resolves.toEqual(
expect.objectContaining({
@ -1852,10 +1831,7 @@ describe('UserResolver', () => {
})
it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith(
'User already has role=',
RoleNames.ROLE_NAME_MODERATOR,
)
expect(logger.error).toBeCalledWith('User already has role=', RoleNames.MODERATOR)
})
})

View File

@ -15,6 +15,7 @@ import { v4 as uuidv4 } from 'uuid'
import { CreateUserArgs } from '@arg/CreateUserArgs'
import { Paginated } from '@arg/Paginated'
import { SearchUsersFilters } from '@arg/SearchUsersFilters'
import { SetUserRoleArgs } from '@arg/SetUserRoleArgs'
import { UnsecureLoginArgs } from '@arg/UnsecureLoginArgs'
import { UpdateUserInfosArgs } from '@arg/UpdateUserInfosArgs'
import { OptInType } from '@enum/OptInType'
@ -70,9 +71,6 @@ import { getKlicktippState } from './util/getKlicktippState'
import { setUserRole, deleteUserRole } from './util/modifyUserRole'
import { validateAlias } from './util/validateAlias'
import { RoleNames } from '@enum/RoleNames'
import { SetUserRoleArgs } from '@arg/SetUserRoleArgs'
const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl']
const DEFAULT_LANGUAGE = 'de'
const isLanguage = (language: string): boolean => {
@ -857,7 +855,7 @@ const canEmailResend = (updatedAt: Date): boolean => {
return !isTimeExpired(updatedAt, CONFIG.EMAIL_CODE_REQUEST_TIME)
}
export function isUserInRole(user: DbUser, role: string): boolean {
export function isUserInRole(user: DbUser, role: string | null | undefined): boolean {
if (user && role) {
for (const userRole of user.userRoles) {
if (userRole.role === role) {

View File

@ -3,7 +3,7 @@ import { UserRole } from '@entity/UserRole'
import { LogError } from '@/server/LogError'
export async function setUserRole(user: DbUser, role: string | null): Promise<void> {
export async function setUserRole(user: DbUser, role: string | null | undefined): Promise<void> {
// if role should be set
if (role) {
// in case user has still no associated userRole

View File

@ -20,7 +20,6 @@ export const contributionLinkFactory = async (
mutation: login,
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
})
console.log('user=', user)
const variables = {
amount: contributionLink.amount,
memo: contributionLink.memo,
@ -33,6 +32,5 @@ export const contributionLinkFactory = async (
}
const result = await mutate({ mutation: createContributionLink, variables })
console.log('link...', result)
return result.data.createContributionLink
}

View File

@ -4,6 +4,7 @@ import { User } from '@entity/User'
import { ApolloServerTestClient } from 'apollo-server-testing'
import { RoleNames } from '@enum/RoleNames'
import { setUserRole } from '@/graphql/resolver/util/modifyUserRole'
import { createUser, setPassword } from '@/seeds/graphql/mutations'
import { UserInterface } from '@/seeds/users/UserInterface'
@ -37,10 +38,7 @@ export const userFactory = async (
if (user.createdAt || user.deletedAt || user.role) {
if (user.createdAt) dbUser.createdAt = user.createdAt
if (user.deletedAt) dbUser.deletedAt = user.deletedAt
if (
user.role &&
(user.role === RoleNames.ROLE_NAME_ADMIN || user.role === RoleNames.ROLE_NAME_MODERATOR)
) {
if (user.role && (user.role === RoleNames.ADMIN || user.role === RoleNames.MODERATOR)) {
await setUserRole(dbUser, user.role)
}
await dbUser.save()

View File

@ -95,8 +95,6 @@ export const searchUsers = gql`
emailConfirmationSend
deletedAt
roles
isAdmin
isModerator
}
}
}

View File

@ -10,5 +10,5 @@ export const peterLustig: UserInterface = {
createdAt: new Date('2020-11-25T10:48:43'),
emailChecked: true,
language: 'de',
role: RoleNames.ROLE_NAME_ADMIN,
role: RoleNames.ADMIN,
}

View File

@ -1,4 +1,4 @@
CONFIG_VERSION=v1.2023-07-04
CONFIG_VERSION=v2.2023-07-07
# SET LOG LEVEL AS NEEDED IN YOUR .ENV
# POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal
@ -7,3 +7,6 @@ CONFIG_VERSION=v1.2023-07-04
# IOTA
IOTA_API_URL=https://chrysalis-nodes.iota.org
IOTA_COMMUNITY_ALIAS=GRADIDO: TestHelloWelt2
# DLT-Connector
DLT_CONNECTOR_PORT=6000

View File

@ -2,4 +2,7 @@ CONFIG_VERSION=$DLT_CONNECTOR_CONFIG_VERSION
#IOTA
IOTA_API_URL=$IOTA_API_URL
IOTA_COMMUNITY_ALIAS=$IOTA_COMMUNITY_ALIAS
IOTA_COMMUNITY_ALIAS=$IOTA_COMMUNITY_ALIAS
# DLT-Connector
DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT

View File

@ -106,4 +106,4 @@ COPY --from=build ${DOCKER_WORKDIR}/log4js-config.json ./log4js-config.json
# COPY --from=build ${DOCKER_WORKDIR}/run ./run
# Run command
CMD /bin/sh -c "yarn run start"
CMD /bin/sh -c "yarn run start"

View File

@ -6,7 +6,7 @@ module.exports = {
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'],
coverageThreshold: {
global: {
lines: 52,
lines: 63,
},
},
setupFiles: ['<rootDir>/test/testSetup.ts'],
@ -14,7 +14,12 @@ module.exports = {
modulePathIgnorePatterns: ['<rootDir>/build/'],
moduleNameMapper: {
'@/(.*)': '<rootDir>/src/$1',
'@enum/(.*)': '<rootDir>/src/graphql/enum/$1',
'@resolver/(.*)': '<rootDir>/src/graphql/resolver/$1',
'@input/(.*)': '<rootDir>/src/graphql/input/$1',
'@proto/(.*)': '<rootDir>/src/proto/$1',
'@test/(.*)': '<rootDir>/test/$1',
'@client/(.*)': '<rootDir>/src/client/$1',
'@entity/(.*)':
// eslint-disable-next-line n/no-process-env
process.env.NODE_ENV === 'development'
@ -27,3 +32,12 @@ module.exports = {
: '<rootDir>/../database/build/src/$1',
},
}
/*
@arg/*": ["src/graphql/arg/*"],
"@enum/*": ["src/graphql/enum/*"],
"@input/*": ["src/graphql/input/*"],
"@resolver/*": ["src/graphql/resolver/*"],
"@scalar/*": ["src/graphql/scalar/*"],
"@test/*": ["test/*"],
"@proto/*" : ["src/proto/*"],
*/

View File

@ -16,20 +16,29 @@
"test": "cross-env TZ=UTC NODE_ENV=development jest --runInBand --forceExit --detectOpenHandles"
},
"dependencies": {
"@apollo/protobufjs": "^1.2.7",
"@apollo/server": "^4.7.5",
"@apollo/utils.fetcher": "^3.0.0",
"@iota/client": "^2.2.4",
"body-parser": "^1.20.2",
"class-validator": "^0.14.0",
"cors": "^2.8.5",
"cross-env": "^7.0.3",
"decimal.js-light": "^2.5.1",
"dotenv": "10.0.0",
"express": "4.17.1",
"graphql": "^16.7.1",
"graphql-scalars": "^1.22.2",
"log4js": "^6.7.1",
"nodemon": "^2.0.20",
"reflect-metadata": "^0.1.13",
"tsconfig-paths": "^4.1.2",
"type-graphql": "^2.0.0-beta.2"
},
"devDependencies": {
"@eslint-community/eslint-plugin-eslint-comments": "^3.2.1",
"@graphql-tools/mock": "^9.0.0",
"@types/cors": "^2.8.13",
"@types/jest": "^27.0.2",
"@types/node": "^18.11.18",
"@types/uuid": "^8.3.4",

View File

@ -8,10 +8,10 @@ const client = new ClientBuilder().node(CONFIG.IOTA_API_URL).build()
/**
* send data message onto iota tangle
* use CONFIG.IOTA_COMMUNITY_ALIAS for index
* @param {string} message - the message as utf based string, will be converted to hex automatically from @iota/client
* @param {string | Uint8Array} message - the message as utf based string, will be converted to hex automatically from @iota/client
* @return {Promise<MessageWrapper>} the iota message typed
*/
function sendMessage(message: string): Promise<MessageWrapper> {
function sendMessage(message: string | Uint8Array): Promise<MessageWrapper> {
return client.message().index(CONFIG.IOTA_COMMUNITY_ALIAS).data(message).submit()
}

View File

@ -8,7 +8,7 @@ const constants = {
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
CONFIG_VERSION: {
DEFAULT: 'DEFAULT',
EXPECTED: 'v1.2023-07-04',
EXPECTED: 'v2.2023-07-07',
CURRENT: '',
},
}
@ -22,6 +22,10 @@ const iota = {
IOTA_COMMUNITY_ALIAS: process.env.IOTA_COMMUNITY_ALIAS ?? 'GRADIDO: TestHelloWelt2',
}
const dltConnector = {
DLT_CONNECTOR_PORT: process.env.DLT_CONNECTOR_PORT || 6000,
}
// Check config version
constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT
if (
@ -38,4 +42,5 @@ export const CONFIG = {
...constants,
...server,
...iota,
...dltConnector,
}

View File

@ -0,0 +1,12 @@
import { registerEnumType } from 'type-graphql'
export enum TransactionType {
CREATION = 1,
SEND = 2,
RECEIVE = 3,
}
registerEnumType(TransactionType, {
name: 'TransactionType', // this one is mandatory
description: 'Type of the transaction', // this one is optional
})

View File

@ -0,0 +1,21 @@
// https://www.npmjs.com/package/@apollo/protobufjs
import { Decimal } from 'decimal.js-light'
import { TransactionType } from '../enum/TransactionType'
import { InputType, Field } from 'type-graphql'
@InputType()
export class TransactionInput {
@Field(() => TransactionType)
type: TransactionType
@Field(() => Decimal)
amount: Decimal
@Field(() => Number)
createdAt: number
// @protoField.d(4, 'string')
// @Field(() => Decimal)
// communitySum: Decimal
}

View File

@ -0,0 +1,115 @@
import 'reflect-metadata'
import { ApolloServer } from '@apollo/server'
import { createApolloTestServer } from '@test/ApolloServerMock'
import assert from 'assert'
jest.mock('@/client/IotaClient', () => {
return {
sendMessage: jest.fn().mockReturnValue({
messageId: '5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710',
}),
}
})
let apolloTestServer: ApolloServer
describe('Transaction Resolver Test', () => {
beforeAll(async () => {
apolloTestServer = await createApolloTestServer()
})
it('test version query', async () => {
const response = await apolloTestServer.executeOperation({
query: '{ version }',
})
// Note the use of Node's assert rather than Jest's expect; if using
// TypeScript, `assert`` will appropriately narrow the type of `body`
// and `expect` will not.
// Source: https://www.apollographql.com/docs/apollo-server/testing/testing
assert(response.body.kind === 'single')
expect(response.body.singleResult.errors).toBeUndefined()
expect(response.body.singleResult.data?.version).toBe('0.1')
})
it('test mocked sendTransaction', async () => {
const response = await apolloTestServer.executeOperation({
query: 'mutation ($input: TransactionInput!) { sendTransaction(data: $input) }',
variables: {
input: {
type: 'SEND',
amount: '10',
createdAt: 1688992436,
},
},
})
assert(response.body.kind === 'single')
expect(response.body.singleResult.errors).toBeUndefined()
expect(response.body.singleResult.data?.sendTransaction).toBe(
'5498130bc3918e1a7143969ce05805502417e3e1bd596d3c44d6a0adeea22710',
)
})
it('test mocked sendTransaction invalid transactionType ', async () => {
const response = await apolloTestServer.executeOperation({
query: 'mutation ($input: TransactionInput!) { sendTransaction(data: $input) }',
variables: {
input: {
type: 'INVALID',
amount: '10',
createdAt: 1688992436,
},
},
})
assert(response.body.kind === 'single')
expect(response.body.singleResult).toMatchObject({
errors: [
{
message:
'Variable "$input" got invalid value "INVALID" at "input.type"; Value "INVALID" does not exist in "TransactionType" enum.',
},
],
})
})
it('test mocked sendTransaction invalid amount ', async () => {
const response = await apolloTestServer.executeOperation({
query: 'mutation ($input: TransactionInput!) { sendTransaction(data: $input) }',
variables: {
input: {
type: 'SEND',
amount: 'no number',
createdAt: 1688992436,
},
},
})
assert(response.body.kind === 'single')
expect(response.body.singleResult).toMatchObject({
errors: [
{
message:
'Variable "$input" got invalid value "no number" at "input.amount"; Expected type "Decimal". [DecimalError] Invalid argument: no number',
},
],
})
})
it('test mocked sendTransaction invalid created date ', async () => {
const response = await apolloTestServer.executeOperation({
query: 'mutation ($input: TransactionInput!) { sendTransaction(data: $input) }',
variables: {
input: {
type: 'SEND',
amount: '10',
createdAt: '2023-03-02T10:12:00',
},
},
})
assert(response.body.kind === 'single')
expect(response.body.singleResult).toMatchObject({
errors: [
{
message:
'Variable "$input" got invalid value "2023-03-02T10:12:00" at "input.createdAt"; Float cannot represent non numeric value: "2023-03-02T10:12:00"',
},
],
})
})
})

View File

@ -0,0 +1,31 @@
import { Resolver, Query, Arg, Mutation } from 'type-graphql'
import { TransactionInput } from '@input/TransactionInput'
import { TransactionBody } from '@proto/TransactionBody'
import { sendMessage as iotaSendMessage } from '@/client/IotaClient'
@Resolver()
export class TransactionResolver {
// Why a dummy function?
// to prevent this error by start:
// GeneratingSchemaError: Some errors occurred while generating GraphQL schema:
// Type Query must define one or more fields.
// it seems that at least one query must be defined
// https://github.com/ardatan/graphql-tools/issues/764
@Query(() => String)
version(): string {
return '0.1'
}
@Mutation(() => String)
async sendTransaction(
@Arg('data')
transaction: TransactionInput,
): Promise<string> {
const message = TransactionBody.fromObject(transaction)
const messageBuffer = TransactionBody.encode(message).finish()
const resultMessage = await iotaSendMessage(messageBuffer)
return resultMessage.messageId
}
}

View File

@ -0,0 +1,30 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { Decimal } from 'decimal.js-light'
import { GraphQLScalarType, Kind, ValueNode } from 'graphql'
export const DecimalScalar = new GraphQLScalarType<Decimal, string>({
name: 'Decimal',
description: 'The `Decimal` scalar type to represent currency values',
serialize(value: unknown): string {
if (!(value instanceof Decimal)) {
throw new TypeError(`Value is not a Decimal: ${value}`)
}
return value.toString()
},
parseValue(value: unknown): Decimal {
if (typeof value !== 'string') {
throw new TypeError('Decimal values must be strings')
}
return new Decimal(value)
},
parseLiteral(ast: ValueNode): Decimal {
if (ast.kind !== Kind.STRING) {
throw new TypeError(`${String(ast)} is not a valid decimal value.`)
}
return new Decimal(ast.value)
},
})

View File

@ -0,0 +1,13 @@
import { Decimal } from 'decimal.js-light'
import { GraphQLSchema } from 'graphql'
import { buildSchema } from 'type-graphql'
import { DecimalScalar } from './scalar/Decimal'
import { TransactionResolver } from './resolver/TransactionsResolver'
export const schema = async (): Promise<GraphQLSchema> => {
return buildSchema({
resolvers: [TransactionResolver],
scalarsMap: [{ type: Decimal, scalar: DecimalScalar }],
})
}

View File

@ -1,34 +1,16 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
sendMessage as iotaSendMessage,
receiveMessage as iotaReceiveMessage,
} from '@/client/IotaClient'
import { CONFIG } from '@/config'
import { IndexationPayload } from '@iota/client/lib/types'
import { logger } from './server/logger'
import createServer from './server/createServer'
async function main() {
const now = new Date()
const messageString = 'Hello World - ' + now.toString()
const messageHexString = Buffer.from(messageString, 'utf8').toString('hex')
const indexHexString = Buffer.from(CONFIG.IOTA_COMMUNITY_ALIAS, 'utf8').toString('hex')
// eslint-disable-next-line no-console
console.log(`DLT_CONNECTOR_PORT=${CONFIG.DLT_CONNECTOR_PORT}`)
const { app } = await createServer()
const iotaSendedMessage = await iotaSendMessage(messageString)
if (iotaSendedMessage && iotaSendedMessage.messageId) {
logger.info('Hello World Message send to iota, get messageId: %s', iotaSendedMessage.messageId)
const iotaReceivedMessage = await iotaReceiveMessage(iotaSendedMessage.messageId)
const indexationPayload = iotaReceivedMessage.message.payload as IndexationPayload
if (
indexationPayload.index.toString() === indexHexString ||
indexationPayload.data.toString() === messageHexString
) {
logger.info('Hello World Message received unchanged from Iota')
} else {
logger.error('Hello World Message changed on Tangle!!!')
}
}
app.listen(CONFIG.DLT_CONNECTOR_PORT, () => {
// eslint-disable-next-line no-console
console.log(`Server is running at http://localhost:${CONFIG.DLT_CONNECTOR_PORT}`)
})
}
main().catch((e) => {

View File

@ -0,0 +1,36 @@
import 'reflect-metadata'
import { TransactionType } from '@enum/TransactionType'
import { TransactionInput } from '@input/TransactionInput'
import Decimal from 'decimal.js-light'
import { TransactionBody } from './TransactionBody'
describe('proto/TransactionBodyTest', () => {
it('test compatible with graphql/input/TransactionInput', async () => {
// test data
const type = TransactionType.SEND
const amount = new Decimal('10')
const createdAt = 1688992436
// init both objects
// graphql input object
const transactionInput = new TransactionInput()
transactionInput.type = type
transactionInput.amount = amount
transactionInput.createdAt = createdAt
// protobuf object
const transactionBody = new TransactionBody()
transactionBody.type = type
transactionBody.amount = amount.toString()
transactionBody.createdAt = createdAt
// create protobuf object from graphql Input object
const message = TransactionBody.fromObject(transactionInput)
// serialize both protobuf objects
const messageBuffer = TransactionBody.encode(message).finish()
const messageBuffer2 = TransactionBody.encode(transactionBody).finish()
// compare
expect(messageBuffer).toStrictEqual(messageBuffer2)
})
})

View File

@ -0,0 +1,18 @@
import { TransactionType } from '../graphql/enum/TransactionType'
import { Field, Message } from '@apollo/protobufjs'
// https://www.npmjs.com/package/@apollo/protobufjs
// eslint-disable-next-line no-use-before-define
export class TransactionBody extends Message<TransactionBody> {
@Field.d(1, TransactionType)
type: TransactionType
@Field.d(2, 'string')
amount: string
@Field.d(3, 'uint64')
createdAt: number
// @protoField.d(4, 'string')
// communitySum: Decimal
}

View File

@ -0,0 +1,27 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { logger } from '@test/testSetup'
import { LogError } from './LogError'
describe('LogError', () => {
it('logs an Error when created', () => {
/* eslint-disable-next-line no-new */
new LogError('new LogError')
expect(logger.error).toBeCalledWith('new LogError')
})
it('logs an Error including additional data when created', () => {
/* eslint-disable-next-line no-new */
new LogError('new LogError', { some: 'data' })
expect(logger.error).toBeCalledWith('new LogError', { some: 'data' })
})
it('does not contain additional data in Error object when thrown', () => {
try {
throw new LogError('new LogError', { someWeirdValue123: 'arbitraryData456' })
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
} catch (e: any) {
expect(e.stack).not.toMatch(/(someWeirdValue123|arbitraryData456)/i)
}
})
})

View File

@ -0,0 +1,10 @@
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { logger } from './logger'
export class LogError extends Error {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(msg: string, ...details: any[]) {
super(msg)
logger.error(msg, ...details)
}
}

View File

@ -0,0 +1,8 @@
import corsLib from 'cors'
const corsOptions = {
origin: '*',
exposedHeaders: ['token'],
}
export const cors = corsLib(corsOptions)

View File

@ -0,0 +1,55 @@
import 'reflect-metadata'
import { ApolloServer } from '@apollo/server'
import { expressMiddleware } from '@apollo/server/express4'
import express, { Express } from 'express'
// graphql
import { schema } from '@/graphql/schema'
import { logger as dltLogger } from './logger'
import { Logger } from 'log4js'
import cors from 'cors'
import bodyParser from 'body-parser'
type ServerDef = { apollo: ApolloServer; app: Express }
interface MyContext {
token?: string
}
const createServer = async (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// context: any = serverContext,
logger: Logger = dltLogger,
// localization: i18n.I18n = i18n,
): Promise<ServerDef> => {
logger.addContext('user', 'unknown')
logger.debug('createServer...')
// Express Server
const app = express()
// Apollo Server
const apollo = new ApolloServer<MyContext>({
schema: await schema(),
introspection: true,
// context,
// plugins
logger,
})
await apollo.start()
app.use(
'/',
cors<cors.CorsRequest>(),
bodyParser.json(),
expressMiddleware(apollo, {
context: async ({ req }) => ({ token: req.headers.token }),
}),
)
logger.debug('createServer...successful')
return { apollo, app }
}
export default createServer

View File

@ -0,0 +1,19 @@
import { ApolloServer } from '@apollo/server'
import { addMocksToSchema } from '@graphql-tools/mock'
import { schema } from '@/graphql/schema'
let apolloTestServer: ApolloServer
export async function createApolloTestServer() {
if (apolloTestServer === undefined) {
apolloTestServer = new ApolloServer({
// addMocksToSchema accepts a schema instance and provides
// mocked data for each field in the schema
schema: addMocksToSchema({
schema: await schema(),
preserveResolvers: true,
}),
})
}
return apolloTestServer
}

View File

@ -48,7 +48,13 @@
"baseUrl": ".", /* Base directory to resolve non-absolute module names. */
"paths": { /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
"@/*": ["src/*"],
"@arg/*": ["src/graphql/arg/*"],
"@enum/*": ["src/graphql/enum/*"],
"@input/*": ["src/graphql/input/*"],
"@resolver/*": ["src/graphql/resolver/*"],
"@scalar/*": ["src/graphql/scalar/*"],
"@test/*": ["test/*"],
"@proto/*" : ["src/proto/*"],
/* external */
},
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */

View File

@ -20,7 +20,7 @@
resolved "https://registry.yarnpkg.com/@apollo/cache-control-types/-/cache-control-types-1.0.3.tgz#5da62cf64c3b4419dabfef4536b57a40c8ff0b47"
integrity sha512-F17/vCp7QVwom9eG7ToauIKdAxpSoadsJnqIfyryLFSkLSOEqu+eC5Z3N8OXcUVStuOMcNHlyraRsA6rRICu4g==
"@apollo/protobufjs@1.2.7":
"@apollo/protobufjs@1.2.7", "@apollo/protobufjs@^1.2.7":
version "1.2.7"
resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.2.7.tgz#3a8675512817e4a046a897e5f4f16415f16a7d8a"
integrity sha512-Lahx5zntHPZia35myYDBRuF58tlwPskwHc5CWBZC/4bMKB6siTBWwtMrkqXcsNwQiFSzSx5hKdRPUmemrEp3Gg==
@ -105,6 +105,11 @@
resolved "https://registry.yarnpkg.com/@apollo/utils.fetcher/-/utils.fetcher-2.0.1.tgz#2f6e3edc8ce79fbe916110d9baaddad7e13d955f"
integrity sha512-jvvon885hEyWXd4H6zpWeN3tl88QcWnHp5gWF5OPF34uhvoR+DFqcNxs9vrRaBBSY3qda3Qe0bdud7tz2zGx1A==
"@apollo/utils.fetcher@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@apollo/utils.fetcher/-/utils.fetcher-3.0.0.tgz#1eb49f95a09fc7e34f9e000af29ff5ec05f808bf"
integrity sha512-WL4pabs5TwWyl2ho0DMk5uRtsD4ORsP/7po83y03CrkCCBAB+E4cs6OteLPaQtizYGiBfMpANxWi11Cy3pwsUA==
"@apollo/utils.isnodelike@^2.0.0", "@apollo/utils.isnodelike@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@apollo/utils.isnodelike/-/utils.isnodelike-2.0.1.tgz#08a7e50f08d2031122efa25af089d1c6ee609f31"
@ -175,19 +180,19 @@
integrity sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg==
"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
version "7.22.6"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.6.tgz#aafafbe86e9a1679d876b99dc46382964ef72494"
integrity sha512-HPIyDa6n+HKw5dEuway3vVAhBboYCtREBMp+IWeseZy6TFtzn6MHkCH2KKYUOC/vKKwgSMHQW4htBOrmuRPXfw==
version "7.22.8"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.8.tgz#386470abe884302db9c82e8e5e87be9e46c86785"
integrity sha512-75+KxFB4CZqYRXjx4NlR4J7yGvKumBuZTmV4NV6v09dVXXkuYVYLT68N6HCzLvfJ+fWCxQsntNzKwwIXL4bHnw==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.22.5"
"@babel/generator" "^7.22.5"
"@babel/generator" "^7.22.7"
"@babel/helper-compilation-targets" "^7.22.6"
"@babel/helper-module-transforms" "^7.22.5"
"@babel/helpers" "^7.22.6"
"@babel/parser" "^7.22.6"
"@babel/parser" "^7.22.7"
"@babel/template" "^7.22.5"
"@babel/traverse" "^7.22.6"
"@babel/traverse" "^7.22.8"
"@babel/types" "^7.22.5"
"@nicolo-ribaudo/semver-v6" "^6.3.3"
convert-source-map "^1.7.0"
@ -195,10 +200,10 @@
gensync "^1.0.0-beta.2"
json5 "^2.2.2"
"@babel/generator@^7.22.5", "@babel/generator@^7.7.2":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.5.tgz#1e7bf768688acfb05cf30b2369ef855e82d984f7"
integrity sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==
"@babel/generator@^7.22.7", "@babel/generator@^7.7.2":
version "7.22.7"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.7.tgz#a6b8152d5a621893f2c9dacf9a4e286d520633d5"
integrity sha512-p+jPjMG+SI8yvIaxGgeW24u7q9+5+TGpZh8/CuB7RhBKd7RCy8FayNEFNNKrNK/eUcY/4ExQqLmyrvBXKsIcwQ==
dependencies:
"@babel/types" "^7.22.5"
"@jridgewell/gen-mapping" "^0.3.2"
@ -309,10 +314,10 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.5", "@babel/parser@^7.22.6":
version "7.22.6"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.6.tgz#201f8b47be20c76c7c5743b9c16129760bf9a975"
integrity sha512-EIQu22vNkceq3LbjAq7knDf/UmtI2qbcNI8GRBlijez6TpQLvSodJPYfydQmNA5buwkxxxa/PVI44jjYZ+/cLw==
"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.5", "@babel/parser@^7.22.7":
version "7.22.7"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae"
integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
@ -414,18 +419,18 @@
"@babel/parser" "^7.22.5"
"@babel/types" "^7.22.5"
"@babel/traverse@^7.22.5", "@babel/traverse@^7.22.6", "@babel/traverse@^7.7.2":
version "7.22.6"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.6.tgz#8f2f83a5c588251584914debeee38f35f661a300"
integrity sha512-53CijMvKlLIDlOTrdWiHileRddlIiwUIyCKqYa7lYnnPldXCG5dUSN38uT0cA6i7rHWNKJLH0VU/Kxdr1GzB3w==
"@babel/traverse@^7.22.5", "@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8", "@babel/traverse@^7.7.2":
version "7.22.8"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.8.tgz#4d4451d31bc34efeae01eac222b514a77aa4000e"
integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==
dependencies:
"@babel/code-frame" "^7.22.5"
"@babel/generator" "^7.22.5"
"@babel/generator" "^7.22.7"
"@babel/helper-environment-visitor" "^7.22.5"
"@babel/helper-function-name" "^7.22.5"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/parser" "^7.22.6"
"@babel/parser" "^7.22.7"
"@babel/types" "^7.22.5"
debug "^4.1.0"
globals "^11.1.0"
@ -499,6 +504,34 @@
"@graphql-tools/utils" "^9.2.1"
tslib "^2.4.0"
"@graphql-tools/merge@^9.0.0":
version "9.0.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-9.0.0.tgz#b0a3636c82716454bff88e9bb40108b0471db281"
integrity sha512-J7/xqjkGTTwOJmaJQJ2C+VDBDOWJL3lKrHJN4yMaRLAJH3PosB7GiPRaSDZdErs0+F77sH2MKs2haMMkywzx7Q==
dependencies:
"@graphql-tools/utils" "^10.0.0"
tslib "^2.4.0"
"@graphql-tools/mock@^9.0.0":
version "9.0.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-9.0.0.tgz#9d4cd3d41333b2c09fee4f248a236aa959906b82"
integrity sha512-Vbb4RNTT9T3fXjmzACcflOh79vKBaC/J21eCJ0eug1ZdaM2QXVHQ3lxE6HNOlAENHXjwJINz1AnKsvF3bpeSKA==
dependencies:
"@graphql-tools/schema" "^10.0.0"
"@graphql-tools/utils" "^10.0.0"
fast-json-stable-stringify "^2.1.0"
tslib "^2.4.0"
"@graphql-tools/schema@^10.0.0":
version "10.0.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-10.0.0.tgz#7b5f6b6a59f51c927de8c9069bde4ebbfefc64b3"
integrity sha512-kf3qOXMFcMs2f/S8Y3A8fm/2w+GaHAkfr3Gnhh2LOug/JgpY/ywgFVxO3jOeSpSEdoYcDKLcXVjMigNbY4AdQg==
dependencies:
"@graphql-tools/merge" "^9.0.0"
"@graphql-tools/utils" "^10.0.0"
tslib "^2.4.0"
value-or-promise "^1.0.12"
"@graphql-tools/schema@^9.0.0":
version "9.0.19"
resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-9.0.19.tgz#c4ad373b5e1b8a0cf365163435b7d236ebdd06e7"
@ -509,6 +542,15 @@
tslib "^2.4.0"
value-or-promise "^1.0.12"
"@graphql-tools/utils@^10.0.0":
version "10.0.3"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-10.0.3.tgz#e5d5b217ba643b7b67a35b50086b5d831aadb71c"
integrity sha512-6uO41urAEIs4sXQT2+CYGsUTkHkVo/2MpM/QjoHj6D6xoEF2woXHBpdAVi0HKIInDwZqWgEYOwIFez0pERxa1Q==
dependencies:
"@graphql-typed-document-node/core" "^3.1.1"
dset "^3.1.2"
tslib "^2.4.0"
"@graphql-tools/utils@^9.2.1":
version "9.2.1"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-9.2.1.tgz#1b3df0ef166cfa3eae706e3518b17d5922721c57"
@ -816,16 +858,16 @@
fastq "^1.6.0"
"@pkgr/utils@^2.3.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.1.tgz#adf291d0357834c410ce80af16e711b56c7b1cd3"
integrity sha512-JOqwkgFEyi+OROIyq7l4Jy28h/WwhDnG/cPkXG2Z1iFbubB6jsHW1NDvmyOzTBxHr3yg68YGirmh1JUgMqa+9w==
version "2.4.2"
resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc"
integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==
dependencies:
cross-spawn "^7.0.3"
fast-glob "^3.2.12"
fast-glob "^3.3.0"
is-glob "^4.0.3"
open "^9.1.0"
picocolors "^1.0.0"
tslib "^2.5.0"
tslib "^2.6.0"
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
@ -967,6 +1009,13 @@
dependencies:
"@types/node" "*"
"@types/cors@^2.8.13":
version "2.8.13"
resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94"
integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==
dependencies:
"@types/node" "*"
"@types/express-serve-static-core@^4.17.30", "@types/express-serve-static-core@^4.17.33":
version "4.17.35"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz#c95dd4424f0d32e525d23812aa8ab8e4d3906c4f"
@ -1060,9 +1109,9 @@
form-data "^3.0.0"
"@types/node@*", "@types/node@^20.1.2":
version "20.3.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.3.tgz#329842940042d2b280897150e023e604d11657d6"
integrity sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==
version "20.4.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.1.tgz#a6033a8718653c50ac4962977e14d0f984d9527d"
integrity sha512-JIzsAvJeA/5iY6Y/OxZbv1lUcc8dNSE77lb2gnBH+/PJ3lFR1Ccvgwl5JWnHAkNHcRsT0TbpVOsiMKZ1F/yyJg==
"@types/node@^18.11.18":
version "18.16.19"
@ -1134,14 +1183,14 @@
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@^5.57.1":
version "5.61.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.61.0.tgz#a1a5290cf33863b4db3fb79350b3c5275a7b1223"
integrity sha512-A5l/eUAug103qtkwccSCxn8ZRwT+7RXWkFECdA4Cvl1dOlDUgTpAOfSEElZn2uSUxhdDpnCdetrf0jvU4qrL+g==
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db"
integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==
dependencies:
"@eslint-community/regexpp" "^4.4.0"
"@typescript-eslint/scope-manager" "5.61.0"
"@typescript-eslint/type-utils" "5.61.0"
"@typescript-eslint/utils" "5.61.0"
"@typescript-eslint/scope-manager" "5.62.0"
"@typescript-eslint/type-utils" "5.62.0"
"@typescript-eslint/utils" "5.62.0"
debug "^4.3.4"
graphemer "^1.4.0"
ignore "^5.2.0"
@ -1150,71 +1199,71 @@
tsutils "^3.21.0"
"@typescript-eslint/parser@^5.57.1":
version "5.61.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.61.0.tgz#7fbe3e2951904bb843f8932ebedd6e0635bffb70"
integrity sha512-yGr4Sgyh8uO6fSi9hw3jAFXNBHbCtKKFMdX2IkT3ZqpKmtAq3lHS4ixB/COFuAIJpwl9/AqF7j72ZDWYKmIfvg==
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7"
integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==
dependencies:
"@typescript-eslint/scope-manager" "5.61.0"
"@typescript-eslint/types" "5.61.0"
"@typescript-eslint/typescript-estree" "5.61.0"
"@typescript-eslint/scope-manager" "5.62.0"
"@typescript-eslint/types" "5.62.0"
"@typescript-eslint/typescript-estree" "5.62.0"
debug "^4.3.4"
"@typescript-eslint/scope-manager@5.61.0":
version "5.61.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.61.0.tgz#b670006d069c9abe6415c41f754b1b5d949ef2b2"
integrity sha512-W8VoMjoSg7f7nqAROEmTt6LoBpn81AegP7uKhhW5KzYlehs8VV0ZW0fIDVbcZRcaP3aPSW+JZFua+ysQN+m/Nw==
"@typescript-eslint/scope-manager@5.62.0":
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c"
integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==
dependencies:
"@typescript-eslint/types" "5.61.0"
"@typescript-eslint/visitor-keys" "5.61.0"
"@typescript-eslint/types" "5.62.0"
"@typescript-eslint/visitor-keys" "5.62.0"
"@typescript-eslint/type-utils@5.61.0":
version "5.61.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.61.0.tgz#e90799eb2045c4435ea8378cb31cd8a9fddca47a"
integrity sha512-kk8u//r+oVK2Aj3ph/26XdH0pbAkC2RiSjUYhKD+PExemG4XSjpGFeyZ/QM8lBOa7O8aGOU+/yEbMJgQv/DnCg==
"@typescript-eslint/type-utils@5.62.0":
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a"
integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==
dependencies:
"@typescript-eslint/typescript-estree" "5.61.0"
"@typescript-eslint/utils" "5.61.0"
"@typescript-eslint/typescript-estree" "5.62.0"
"@typescript-eslint/utils" "5.62.0"
debug "^4.3.4"
tsutils "^3.21.0"
"@typescript-eslint/types@5.61.0":
version "5.61.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.61.0.tgz#e99ff11b5792d791554abab0f0370936d8ca50c0"
integrity sha512-ldyueo58KjngXpzloHUog/h9REmHl59G1b3a5Sng1GfBo14BkS3ZbMEb3693gnP1k//97lh7bKsp6/V/0v1veQ==
"@typescript-eslint/types@5.62.0":
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
"@typescript-eslint/typescript-estree@5.61.0":
version "5.61.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.61.0.tgz#4c7caca84ce95bb41aa585d46a764bcc050b92f3"
integrity sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==
"@typescript-eslint/typescript-estree@5.62.0":
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==
dependencies:
"@typescript-eslint/types" "5.61.0"
"@typescript-eslint/visitor-keys" "5.61.0"
"@typescript-eslint/types" "5.62.0"
"@typescript-eslint/visitor-keys" "5.62.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.61.0", "@typescript-eslint/utils@^5.10.0":
version "5.61.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.61.0.tgz#5064838a53e91c754fffbddd306adcca3fe0af36"
integrity sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==
"@typescript-eslint/utils@5.62.0", "@typescript-eslint/utils@^5.10.0":
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86"
integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@types/json-schema" "^7.0.9"
"@types/semver" "^7.3.12"
"@typescript-eslint/scope-manager" "5.61.0"
"@typescript-eslint/types" "5.61.0"
"@typescript-eslint/typescript-estree" "5.61.0"
"@typescript-eslint/scope-manager" "5.62.0"
"@typescript-eslint/types" "5.62.0"
"@typescript-eslint/typescript-estree" "5.62.0"
eslint-scope "^5.1.1"
semver "^7.3.7"
"@typescript-eslint/visitor-keys@5.61.0":
version "5.61.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.61.0.tgz#c79414fa42158fd23bd2bb70952dc5cdbb298140"
integrity sha512-50XQ5VdbWrX06mQXhy93WywSFZZGsv3EOjq+lqp6WC2t+j3mb6A9xYVdrRxafvK88vg9k9u+CT4l6D8PEatjKg==
"@typescript-eslint/visitor-keys@5.62.0":
version "5.62.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e"
integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==
dependencies:
"@typescript-eslint/types" "5.61.0"
"@typescript-eslint/types" "5.62.0"
eslint-visitor-keys "^3.3.0"
abab@^2.0.3, abab@^2.0.5:
@ -1264,9 +1313,9 @@ acorn@^7.1.1:
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.2.4, acorn@^8.4.1, acorn@^8.9.0:
version "8.9.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.9.0.tgz#78a16e3b2bcc198c10822786fa6679e245db5b59"
integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==
version "8.10.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
agent-base@6:
version "6.0.2"
@ -1559,7 +1608,7 @@ body-parser@1.20.1:
type-is "~1.6.18"
unpipe "1.0.0"
body-parser@^1.20.0:
body-parser@^1.20.0, body-parser@^1.20.2:
version "1.20.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
@ -1694,9 +1743,9 @@ camelcase@^6.2.0:
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
caniuse-lite@^1.0.30001503:
version "1.0.30001512"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz#7450843fb581c39f290305a83523c7a9ef0d4cb4"
integrity sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==
version "1.0.30001515"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz#418aefeed9d024cd3129bfae0ccc782d4cb8f12b"
integrity sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==
chalk@^2.0.0, chalk@^2.4.2:
version "2.4.2"
@ -1796,9 +1845,9 @@ code-point-at@^1.0.0:
integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==
collect-v8-coverage@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59"
integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==
version "1.0.2"
resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9"
integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==
color-convert@^1.9.0:
version "1.9.3"
@ -1993,6 +2042,11 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"
decimal.js-light@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934"
integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==
decimal.js@^10.2.1:
version "10.4.3"
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23"
@ -2139,15 +2193,20 @@ dotenv@10.0.0:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==
dset@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.2.tgz#89c436ca6450398396dc6538ea00abc0c54cd45a"
integrity sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
electron-to-chromium@^1.4.431:
version "1.4.449"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.449.tgz#79ffe4514c81c35d4eb13030a63ff3383a8cc655"
integrity sha512-TxLRpRUj/107ATefeP8VIUWNOv90xJxZZbCW/eIbSZQiuiFANCx2b7u+GbVc9X4gU+xnbvypNMYVM/WArE1DNQ==
version "1.4.455"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.455.tgz#81fe4353ac970eb971c07088c8da8b7f6280ddc9"
integrity sha512-8tgdX0Odl24LtmLwxotpJCVjIndN559AvaOtd67u+2mo+IDsgsTF580NB+uuDCqsHw8yFg53l5+imFV9Fw3cbA==
emittery@^0.8.1:
version "0.8.1"
@ -2676,7 +2735,7 @@ fast-diff@^1.1.2:
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0"
integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.9:
fast-glob@^3.2.9, fast-glob@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.0.tgz#7c40cb491e1e2ed5664749e87bfb516dbe8727c0"
integrity sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==
@ -2687,7 +2746,7 @@ fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.9:
merge2 "^1.3.0"
micromatch "^4.0.4"
fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0:
fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
@ -2993,13 +3052,13 @@ globby@^11.1.0:
slash "^3.0.0"
globby@^13.1.3:
version "13.2.1"
resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.1.tgz#986d44187ba6a9fc4aa9b16caf0ab9a04db94ae9"
integrity sha512-DPCBxctI7dN4EeIqjW2KGqgdcUMbrhJ9AzON+PlxCtvppWhubTLD4+a0GFxiym14ZvacUydTPjLPc2DlKz7EIg==
version "13.2.2"
resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.2.tgz#63b90b1bf68619c2135475cbd4e71e66aa090592"
integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==
dependencies:
dir-glob "^3.0.1"
fast-glob "^3.2.11"
ignore "^5.2.0"
fast-glob "^3.3.0"
ignore "^5.2.4"
merge2 "^1.4.1"
slash "^4.0.0"
@ -3027,6 +3086,13 @@ graphql-query-complexity@^0.12.0:
dependencies:
lodash.get "^4.4.2"
graphql-scalars@^1.22.2:
version "1.22.2"
resolved "https://registry.yarnpkg.com/graphql-scalars/-/graphql-scalars-1.22.2.tgz#6326e6fe2d0ad4228a9fea72a977e2bf26b86362"
integrity sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==
dependencies:
tslib "^2.5.0"
graphql-subscriptions@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-2.0.0.tgz#11ec181d475852d8aec879183e8e1eb94f2eb79a"
@ -4342,9 +4408,9 @@ node-int64@^0.4.0:
integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
node-releases@^2.0.12:
version "2.0.12"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039"
integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==
version "2.0.13"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d"
integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==
nodemon@^2.0.20:
version "2.0.22"
@ -4404,9 +4470,9 @@ number-is-nan@^1.0.0:
integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==
nwsapi@^2.2.0:
version "2.2.6"
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.6.tgz#f876bd7ae9509cac72c640826355abf63d3c326a"
integrity sha512-vSZ4miHQ4FojLjmz2+ux4B0/XA16jfwt/LBzIUftDpRd8tujHFkXjMyLwjS08fIZCzesj2z7gJukOKJwqebJAQ==
version "2.2.7"
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30"
integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==
object-assign@^4, object-assign@^4.1.0:
version "4.1.1"
@ -4816,6 +4882,11 @@ reduce-flatten@^2.0.0:
resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27"
integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==
reflect-metadata@^0.1.13:
version "0.1.13"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
regexp-tree@~0.1.1:
version "0.1.27"
resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd"
@ -4976,21 +5047,21 @@ saxes@^5.0.1:
xmlchars "^2.2.0"
semver@7.x, semver@^7.0.0, semver@^7.3.2, semver@^7.3.7, semver@^7.3.8, semver@^7.5.0:
version "7.5.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
semver@^5.4.1, semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
version "5.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
semver@^6.0.0, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@~7.0.0:
version "7.0.0"
@ -5576,7 +5647,7 @@ tslib@^1.8.1, tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.4.0, tslib@^2.5.0:
tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3"
integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==
@ -5872,9 +5943,9 @@ which-boxed-primitive@^1.0.2:
is-symbol "^1.0.3"
which-typed-array@^1.1.9:
version "1.1.9"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6"
integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==
version "1.1.10"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.10.tgz#74baa2789991905c2076abb317103b866c64e69e"
integrity sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==
dependencies:
available-typed-arrays "^1.0.5"
call-bind "^1.0.2"