From c01829aa2f0fdecbb09681672169a237fe7ceba6 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Thu, 9 Mar 2023 10:51:08 +0000 Subject: [PATCH 01/33] Move Abstract Database Classes to Common Refactor abstract classes and auth service in such a way that they can be moved to common. --- services/auth/src/database/dataSource.ts | 41 +- .../repositories/abstractRepository.ts | 94 - .../repositories/activeKeyRepository.ts | 16 +- .../database/repositories/keyRepository.ts | 18 +- .../database/repositories/roleRepository.ts | 18 +- .../database/repositories/scopeRepository.ts | 18 +- .../database/repositories/tokenRepository.ts | 18 +- .../database/repositories/userRepository.ts | 18 +- services/auth/test/data/activeKeyData.spec.ts | 6 +- services/auth/test/data/index.spec.ts | 113 +- services/auth/test/data/keyData.spec.ts | 6 +- services/auth/test/data/roleData.spec.ts | 7 +- services/auth/test/data/scopeData.spec.ts | 8 +- services/auth/test/data/tokenData.spec.ts | 7 +- services/auth/test/data/userData.spec.ts | 5 +- .../repositories/abstractRepository.spec.ts | 532 ------ .../repositories/activeKeyRepository.spec.ts | 25 +- .../test/database/repositories/index.spec.ts | 4 +- .../repositories/keyRepository.spec.ts | 22 +- .../repositories/roleRepository.spec.ts | 29 +- .../repositories/scopeRepository.spec.ts | 25 +- .../repositories/tokenRepository.spec.ts | 26 +- .../repositories/userRepository.spec.ts | 31 +- services/common/package-lock.json | 1599 ++++++++++++++++- services/common/package.json | 3 + .../common/src/database/abstractDataSource.ts | 28 + .../common/src/database/abstractRepository.ts | 99 + .../testSuites/abstractRepository.spec.ts | 137 ++ .../src/database/testSuites/create.spec.ts | 58 + .../src/database/testSuites/find.spec.ts | 48 + .../src/database/testSuites/findOne.spec.ts | 59 + .../database/testSuites/findOneOrFail.spec.ts | 66 + .../src/database/testSuites/format.spec.ts | 30 + .../src/database/testSuites/remove.spec.ts | 63 + .../src/database/testSuites/save.spec.ts | 52 + .../src/database/testSuites/types.spec.ts | 68 + .../src/database/testSuites/write.spec.ts | 36 + services/common/src/errors.ts | 128 +- services/common/src/index.ts | 87 +- services/common/src/types.ts | 23 + 40 files changed, 2646 insertions(+), 1025 deletions(-) delete mode 100644 services/auth/src/database/repositories/abstractRepository.ts delete mode 100644 services/auth/test/database/repositories/abstractRepository.spec.ts create mode 100644 services/common/src/database/abstractDataSource.ts create mode 100644 services/common/src/database/abstractRepository.ts create mode 100644 services/common/src/database/testSuites/abstractRepository.spec.ts create mode 100644 services/common/src/database/testSuites/create.spec.ts create mode 100644 services/common/src/database/testSuites/find.spec.ts create mode 100644 services/common/src/database/testSuites/findOne.spec.ts create mode 100644 services/common/src/database/testSuites/findOneOrFail.spec.ts create mode 100644 services/common/src/database/testSuites/format.spec.ts create mode 100644 services/common/src/database/testSuites/remove.spec.ts create mode 100644 services/common/src/database/testSuites/save.spec.ts create mode 100644 services/common/src/database/testSuites/types.spec.ts create mode 100644 services/common/src/database/testSuites/write.spec.ts create mode 100644 services/common/src/types.ts diff --git a/services/auth/src/database/dataSource.ts b/services/auth/src/database/dataSource.ts index 9b5cc870..9496a0b2 100644 --- a/services/auth/src/database/dataSource.ts +++ b/services/auth/src/database/dataSource.ts @@ -5,37 +5,16 @@ import { roleRepository } from './repositories/roleRepository' import { scopeRepository } from './repositories/scopeRepository' import { tokenRepository } from './repositories/tokenRepository' import { userRepository } from './repositories/userRepository' -import { DataSource, DataSourceOptions, EntityTarget, ObjectLiteral } from 'typeorm' - -export class ApplicationDataSource { - private dataSource?: DataSource - public connected = false - - public async initialize(options: DataSourceOptions) { - this.dataSource = new DataSource(options) - await this.dataSource.initialize() - this.connected = true - activeKeyRepository.initialize() - keyRepository.initialize() - roleRepository.initialize() - scopeRepository.initialize() - tokenRepository.initialize() - userRepository.initialize() - } - - public async teardown() { - if (!this.dataSource?.isInitialized) - throw new Error('Data Source has not been initialized!') - - await this.dataSource.destroy() - this.connected = false - } - - public getRepository(target: EntityTarget) { - if (!this.dataSource?.isInitialized) - throw new Error('Data Source has not been initialized!') - - return this.dataSource.getRepository(target) +import { AbstractApplicationDataSource } from '@crosslab/service-common' + +export class ApplicationDataSource extends AbstractApplicationDataSource { + protected initializeRepositories(): void { + activeKeyRepository.initialize(this) + keyRepository.initialize(this) + roleRepository.initialize(this) + scopeRepository.initialize(this) + tokenRepository.initialize(this) + userRepository.initialize(this) } } diff --git a/services/auth/src/database/repositories/abstractRepository.ts b/services/auth/src/database/repositories/abstractRepository.ts deleted file mode 100644 index 0efa64f9..00000000 --- a/services/auth/src/database/repositories/abstractRepository.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { MissingEntityError } from '@crosslab/service-common' -import { - FindManyOptions, - FindOneOptions, - FindOptionsRelations, - Repository, -} from 'typeorm' -import { UninitializedRepositoryError } from '../../types/errors' -import { getModelName, Model, ModelType } from '../model' - -/** - * An abstract class for a repository. - * @typeParam M - Type of the model. - * @typeParam E - Type of the entity target corresponding to the model. - * @typeParam T - Type of the data corresponding to the model. - */ -export abstract class AbstractRepository { - protected repository?: Repository - private model: Model - - constructor(model: Model) { - this.model = model - } - - protected throwUninitializedRepositoryError(): never { - throw new UninitializedRepositoryError(this.model) - } - - abstract initialize(): void - - public async create(data?: ModelType): Promise { - if (!this.repository) this.throwUninitializedRepositoryError() - const model = this.repository.create() - if (data === undefined) return model - await this.write(model, data) - return model - } - - abstract write(model: M, data: ModelType): Promise - - public async save(model: M): Promise { - if (!this.repository) this.throwUninitializedRepositoryError() - return await this.repository.save(model) - } - - public async find(options?: FindManyOptions): Promise { - if (!this.repository) this.throwUninitializedRepositoryError() - const findOptions: FindManyOptions = { - ...(options ?? {}), - relations: options?.relations ?? this.getDefaultFindOptionsRelations(), - } - return await this.repository.find(findOptions) - } - - public async findOne(options: FindOneOptions): Promise { - if (!this.repository) this.throwUninitializedRepositoryError() - const findOptions: FindManyOptions = { - ...options, - relations: options?.relations ?? this.getDefaultFindOptionsRelations(), - } - return await this.repository.findOne(findOptions) - } - - public async findOneOrFail(options: FindOneOptions): Promise { - if (!this.repository) this.throwUninitializedRepositoryError() - const findOptions: FindOneOptions = { - ...options, - relations: options.relations ?? this.getDefaultFindOptionsRelations(), - } - const model = await this.repository.findOne(findOptions) - - if (!model) { - throw new MissingEntityError( - `The requested ${getModelName( - this.model - ).toLowerCase()} does not exist in the database`, - 404 - ) - } - - return model - } - - abstract format(model: M): Promise> - - public async remove(model: M): Promise { - if (!this.repository) this.throwUninitializedRepositoryError() - await this.repository.remove(model) - } - - protected getDefaultFindOptionsRelations(): FindOptionsRelations | undefined { - return undefined - } -} diff --git a/services/auth/src/database/repositories/activeKeyRepository.ts b/services/auth/src/database/repositories/activeKeyRepository.ts index 4d735725..07d51b87 100644 --- a/services/auth/src/database/repositories/activeKeyRepository.ts +++ b/services/auth/src/database/repositories/activeKeyRepository.ts @@ -1,16 +1,22 @@ -import { AbstractRepository } from './abstractRepository' import { ActiveKey } from '../../types/types' import { ActiveKeyModel } from '../model' import { keyRepository } from './keyRepository' -import { AppDataSource } from '../dataSource' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' import { FindOptionsRelations } from 'typeorm' -export class ActiveKeyRepository extends AbstractRepository { +export class ActiveKeyRepository extends AbstractRepository< + ActiveKeyModel, + ActiveKey<'request'>, + ActiveKey<'response'> +> { constructor() { - super(ActiveKeyModel) + super('Active Key') } - public initialize(): void { + public initialize(AppDataSource: AbstractApplicationDataSource): void { this.repository = AppDataSource.getRepository(ActiveKeyModel) } diff --git a/services/auth/src/database/repositories/keyRepository.ts b/services/auth/src/database/repositories/keyRepository.ts index 074c4617..34089dd2 100644 --- a/services/auth/src/database/repositories/keyRepository.ts +++ b/services/auth/src/database/repositories/keyRepository.ts @@ -1,15 +1,21 @@ -import { AbstractRepository } from './abstractRepository' import { Key } from '../../types/types' import { KeyModel } from '../model' -import { AppDataSource } from '../dataSource' import { activeKeyRepository } from './activeKeyRepository' - -export class KeyRepository extends AbstractRepository { +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' + +export class KeyRepository extends AbstractRepository< + KeyModel, + Required, + Key<'response'> +> { constructor() { - super(KeyModel) + super('Key') } - public initialize(): void { + public initialize(AppDataSource: AbstractApplicationDataSource): void { this.repository = AppDataSource.getRepository(KeyModel) } diff --git a/services/auth/src/database/repositories/roleRepository.ts b/services/auth/src/database/repositories/roleRepository.ts index 54590759..f948d00b 100644 --- a/services/auth/src/database/repositories/roleRepository.ts +++ b/services/auth/src/database/repositories/roleRepository.ts @@ -1,17 +1,23 @@ -import { AbstractRepository } from './abstractRepository' import { Role, RoleInit } from '../../generated/types' +import { roleUrlFromId } from '../../methods/utils' import { RoleModel, UserModel } from '../model' import { scopeRepository } from './scopeRepository' -import { AppDataSource } from '../dataSource' -import { roleUrlFromId } from '../../methods/utils' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' import { FindOptionsRelations } from 'typeorm' -export class RoleRepository extends AbstractRepository { +export class RoleRepository extends AbstractRepository< + RoleModel, + Role<'request'>, + Role<'response'> +> { constructor() { - super(RoleModel) + super('Role') } - public initialize(): void { + public initialize(AppDataSource: AbstractApplicationDataSource): void { this.repository = AppDataSource.getRepository(RoleModel) } diff --git a/services/auth/src/database/repositories/scopeRepository.ts b/services/auth/src/database/repositories/scopeRepository.ts index 8a8191aa..36623a38 100644 --- a/services/auth/src/database/repositories/scopeRepository.ts +++ b/services/auth/src/database/repositories/scopeRepository.ts @@ -1,14 +1,20 @@ -import { AbstractRepository } from './abstractRepository' -import { ScopeModel } from '../model' -import { AppDataSource } from '../dataSource' import { Scope } from '../../types/types' +import { ScopeModel } from '../model' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' -export class ScopeRepository extends AbstractRepository { +export class ScopeRepository extends AbstractRepository< + ScopeModel, + Scope<'request'>, + Scope<'response'> +> { constructor() { - super(ScopeModel) + super('Scope') } - public initialize(): void { + public initialize(AppDataSource: AbstractApplicationDataSource): void { this.repository = AppDataSource.getRepository(ScopeModel) } diff --git a/services/auth/src/database/repositories/tokenRepository.ts b/services/auth/src/database/repositories/tokenRepository.ts index 8c3410ea..11ff7496 100644 --- a/services/auth/src/database/repositories/tokenRepository.ts +++ b/services/auth/src/database/repositories/tokenRepository.ts @@ -1,17 +1,23 @@ -import { AbstractRepository } from './abstractRepository' import { Token } from '../../types/types' import { ScopeModel, TokenModel } from '../model' import { scopeRepository } from './scopeRepository' -import { AppDataSource } from '../dataSource' -import { FindOptionsRelations } from 'typeorm' import { userRepository } from './userRepository' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' +import { FindOptionsRelations } from 'typeorm' -export class TokenRepository extends AbstractRepository { +export class TokenRepository extends AbstractRepository< + TokenModel, + Token<'request'>, + Token<'response'> +> { constructor() { - super(TokenModel) + super('Token') } - public initialize(): void { + public initialize(AppDataSource: AbstractApplicationDataSource): void { this.repository = AppDataSource.getRepository(TokenModel) } diff --git a/services/auth/src/database/repositories/userRepository.ts b/services/auth/src/database/repositories/userRepository.ts index 6829dc67..84572b0f 100644 --- a/services/auth/src/database/repositories/userRepository.ts +++ b/services/auth/src/database/repositories/userRepository.ts @@ -1,18 +1,24 @@ -import { hash } from 'bcryptjs' -import { AbstractRepository } from './abstractRepository' import { User, UserInit, UserUpdate } from '../../generated/types' import { userUrlFromId } from '../../methods/utils' -import { AppDataSource } from '../dataSource' import { RoleModel, UserModel } from '../model' import { tokenRepository } from './tokenRepository' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' +import { hash } from 'bcryptjs' import { FindOptionsRelations } from 'typeorm' -export class UserRepository extends AbstractRepository { +export class UserRepository extends AbstractRepository< + UserModel, + UserUpdate<'request'>, + User<'response'> +> { constructor() { - super(UserModel) + super('User') } - public initialize(): void { + public initialize(AppDataSource: AbstractApplicationDataSource): void { this.repository = AppDataSource.getRepository(UserModel) } diff --git a/services/auth/test/data/activeKeyData.spec.ts b/services/auth/test/data/activeKeyData.spec.ts index d79fabbc..e6f0d11c 100644 --- a/services/auth/test/data/activeKeyData.spec.ts +++ b/services/auth/test/data/activeKeyData.spec.ts @@ -1,10 +1,10 @@ -import { ActiveKeyModel } from '../../src/database/model' -import { EntityData } from './index.spec' +import { ActiveKeyRepository } from '../../src/database/repositories/activeKeyRepository' import { keyData } from './keyData.spec' +import { EntityData } from '@crosslab/service-common' export const activeKeyNames = ['active key 1', 'GET /auth active key'] as const export type ActiveKeyName = (typeof activeKeyNames)[number] -export type ActiveKeyData = Record> +export type ActiveKeyData = Record> export const activeKeyData: ActiveKeyData = { 'active key 1': { diff --git a/services/auth/test/data/index.spec.ts b/services/auth/test/data/index.spec.ts index 59e47cd2..5cbf95d7 100644 --- a/services/auth/test/data/index.spec.ts +++ b/services/auth/test/data/index.spec.ts @@ -1,72 +1,27 @@ -import { - ActiveKeyModel, - KeyModel, - Model, - ModelType, - RoleModel, - ScopeModel, - TokenModel, - UserModel, -} from '../../src/database/model' +import { ActiveKeyRepository } from '../../src/database/repositories/activeKeyRepository' +import { KeyRepository } from '../../src/database/repositories/keyRepository' +import { RoleRepository } from '../../src/database/repositories/roleRepository' +import { ScopeRepository } from '../../src/database/repositories/scopeRepository' +import { TokenRepository } from '../../src/database/repositories/tokenRepository' +import { UserRepository } from '../../src/database/repositories/userRepository' import { activeKeyData, ActiveKeyName } from './activeKeyData.spec' import { keyData, KeyName } from './keyData.spec' import { prepareRoleData, RoleName } from './roleData.spec' import { prepareScopeData, ScopeName } from './scopeData.spec' import { prepareTokenData, TokenName } from './tokenData.spec' import { prepareUserData, UserName } from './userData.spec' +import { GenericTestData } from '@crosslab/service-common' -export type ReplaceWith, R> = { - [K in keyof T]: K extends P ? R : T[K] -} -export type RemoveIndex = { - [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K] -} -export type SubstituteType = T extends A - ? B - : T extends object - ? { [K in keyof T]: SubstituteType } - : T -export type Subset = { - [attr in keyof K]?: K[attr] extends object - ? Subset - : K[attr] extends object | null - ? Subset | null - : K[attr] extends object | null | undefined - ? Subset | null | undefined - : K[attr] -} - -export const entityDataKeys = ['request', 'model', 'response'] as const -export interface EntityData { - request: ModelType - model: M - response: ModelType -} - -export type EntityName = M extends ActiveKeyModel - ? ActiveKeyName - : M extends KeyModel - ? KeyName - : M extends RoleModel - ? RoleName - : M extends ScopeModel - ? ScopeName - : M extends TokenModel - ? TokenName - : M extends UserModel - ? UserName - : never - -export type PartialTestData = Record, EntityData> - -export interface TestData { - activeKeys: PartialTestData - keys: PartialTestData - roles: PartialTestData - scopes: PartialTestData - tokens: PartialTestData - users: PartialTestData -} +export type TestData = GenericTestData< + [ + ['active keys', ActiveKeyName, ActiveKeyRepository], + ['keys', KeyName, KeyRepository], + ['roles', RoleName, RoleRepository], + ['scopes', ScopeName, ScopeRepository], + ['tokens', TokenName, TokenRepository], + ['users', UserName, UserRepository] + ] +> export function prepareTestData(): TestData { const userData = prepareUserData() @@ -74,33 +29,11 @@ export function prepareTestData(): TestData { const tokenData = prepareTokenData(userData) const scopeData = prepareScopeData() return { - activeKeys: activeKeyData, - keys: keyData, - roles: roleData, - scopes: scopeData, - tokens: tokenData, - users: userData, - } -} - -export function getFromTestData( - testData: TestData, - model: { new (): M } -): PartialTestData { - switch (model) { - case ActiveKeyModel: - return testData.activeKeys as PartialTestData - case KeyModel: - return testData.keys as PartialTestData - case RoleModel: - return testData.roles as PartialTestData - case ScopeModel: - return testData.scopes as PartialTestData - case TokenModel: - return testData.tokens as PartialTestData - case UserModel: - return testData.users as PartialTestData - default: - throw Error('No test data exists for the given model') + 'active keys': activeKeyData, + 'keys': keyData, + 'roles': roleData, + 'scopes': scopeData, + 'tokens': tokenData, + 'users': userData, } } diff --git a/services/auth/test/data/keyData.spec.ts b/services/auth/test/data/keyData.spec.ts index a8754525..9a876d94 100644 --- a/services/auth/test/data/keyData.spec.ts +++ b/services/auth/test/data/keyData.spec.ts @@ -1,11 +1,11 @@ /* eslint-disable max-len */ +import { KeyRepository } from '../../src/database/repositories/keyRepository' +import { EntityData } from '@crosslab/service-common' import { JWK } from 'jose' -import { KeyModel } from '../../src/database/model' -import { EntityData } from './index.spec' export const keyNames = ['key 1', 'GET /auth key'] as const export type KeyName = (typeof keyNames)[number] -export type KeyData = Record> +export type KeyData = Record> const keys: Record = { 'key 1': { diff --git a/services/auth/test/data/roleData.spec.ts b/services/auth/test/data/roleData.spec.ts index d4e20a3d..2d2fceae 100644 --- a/services/auth/test/data/roleData.spec.ts +++ b/services/auth/test/data/roleData.spec.ts @@ -1,13 +1,14 @@ import { RoleModel, UserModel } from '../../src/database/model' +import { RoleRepository } from '../../src/database/repositories/roleRepository' import { Role } from '../../src/generated/types' import { roleUrlFromId } from '../../src/methods/utils' -import { EntityData, ReplaceWith, Subset } from './index.spec' import { resolveScope, ScopeName } from './scopeData.spec' import { UserData, UserName } from './userData.spec' +import { EntityData, ReplaceWith, Subset } from '@crosslab/service-common' export const roleNames = ['superadmin', 'user', 'deviceservice', 'device'] as const export type RoleName = (typeof roleNames)[number] -export type RoleData = Record> +export type RoleData = Record> type RoleWithLinks = ReplaceWith< Role, @@ -111,7 +112,7 @@ const roleDataWithLinks: RoleDataWithLinks = { export function resolveRole( roleName: RoleName, userData: Subset -): EntityData { +): EntityData { return { request: { ...roleDataWithLinks[roleName].request, diff --git a/services/auth/test/data/scopeData.spec.ts b/services/auth/test/data/scopeData.spec.ts index 916e65e8..c2d4a083 100644 --- a/services/auth/test/data/scopeData.spec.ts +++ b/services/auth/test/data/scopeData.spec.ts @@ -1,9 +1,9 @@ -import { ScopeModel } from '../../src/database/model' -import { EntityData } from './index.spec' +import { ScopeRepository } from '../../src/database/repositories/scopeRepository' +import { EntityData } from '@crosslab/service-common' export const scopeNames = ['scope 1', 'scope 2', 'scope 3', 'scope 4', 'scope 5'] as const export type ScopeName = (typeof scopeNames)[number] -export type ScopeData = Record> +export type ScopeData = Record> const scopeData: ScopeData = { 'scope 1': { @@ -43,7 +43,7 @@ const scopeData: ScopeData = { }, } -export function resolveScope(scopeName: ScopeName): EntityData { +export function resolveScope(scopeName: ScopeName): EntityData { return scopeData[scopeName] } diff --git a/services/auth/test/data/tokenData.spec.ts b/services/auth/test/data/tokenData.spec.ts index b3ff1ceb..75f842d5 100644 --- a/services/auth/test/data/tokenData.spec.ts +++ b/services/auth/test/data/tokenData.spec.ts @@ -1,8 +1,9 @@ import { TokenModel, UserModel } from '../../src/database/model' +import { TokenRepository } from '../../src/database/repositories/tokenRepository' import { Token } from '../../src/types/types' -import { EntityData, ReplaceWith, Subset } from './index.spec' import { resolveScope, ScopeName } from './scopeData.spec' import { UserData, UserName } from './userData.spec' +import { EntityData, ReplaceWith, Subset } from '@crosslab/service-common' export const tokenNames = [ 'superadmin expired token', @@ -14,7 +15,7 @@ export const tokenNames = [ 'POST /logout valid user token', ] as const export type TokenName = (typeof tokenNames)[number] -export type TokenData = Record> +export type TokenData = Record> type TokenWithLinks = T extends | 'all' @@ -139,7 +140,7 @@ const tokenDataWithLinks: TokenDataWithLinks = { export function resolveToken( tokenName: TokenName, userData: Subset -): EntityData { +): EntityData { return { request: { ...tokenDataWithLinks[tokenName].request, diff --git a/services/auth/test/data/userData.spec.ts b/services/auth/test/data/userData.spec.ts index 409bf6ec..2a7f8cd9 100644 --- a/services/auth/test/data/userData.spec.ts +++ b/services/auth/test/data/userData.spec.ts @@ -1,9 +1,10 @@ import { UserModel } from '../../src/database/model' +import { UserRepository } from '../../src/database/repositories/userRepository' import { User } from '../../src/generated/types' import { userUrlFromId } from '../../src/methods/utils' -import { EntityData, ReplaceWith, Subset } from './index.spec' import { resolveRole, RoleName } from './roleData.spec' import { resolveToken, TokenName } from './tokenData.spec' +import { EntityData, ReplaceWith, Subset } from '@crosslab/service-common' export const userNames = [ 'superadmin', @@ -13,7 +14,7 @@ export const userNames = [ 'POST /logout user', ] as const export type UserName = (typeof userNames)[number] -export type UserData = Record> +export type UserData = Record> type UserWithLinks = ReplaceWith< User, diff --git a/services/auth/test/database/repositories/abstractRepository.spec.ts b/services/auth/test/database/repositories/abstractRepository.spec.ts deleted file mode 100644 index 21048996..00000000 --- a/services/auth/test/database/repositories/abstractRepository.spec.ts +++ /dev/null @@ -1,532 +0,0 @@ -import { MissingEntityError } from '@crosslab/service-common' -import assert, { fail } from 'assert' -import { FindOptionsWhere } from 'typeorm' -import { AppDataSource } from '../../../src/database/dataSource' -import { - ActiveKeyModel, - getModelName, - KeyModel, - Model, - ModelType, - RoleModel, - ScopeModel, - TokenModel, - UserModel, -} from '../../../src/database/model' -import { AbstractRepository } from '../../../src/database/repositories/abstractRepository' -import { - ActiveKeyRepository, - activeKeyRepository, -} from '../../../src/database/repositories/activeKeyRepository' -import { - KeyRepository, - keyRepository, -} from '../../../src/database/repositories/keyRepository' -import { - RoleRepository, - roleRepository, -} from '../../../src/database/repositories/roleRepository' -import { - ScopeRepository, - scopeRepository, -} from '../../../src/database/repositories/scopeRepository' -import { - TokenRepository, - tokenRepository, -} from '../../../src/database/repositories/tokenRepository' -import { - UserRepository, - userRepository, -} from '../../../src/database/repositories/userRepository' -import { activeKeyNames } from '../../data/activeKeyData.spec' -import { - EntityName, - getFromTestData, - PartialTestData, - TestData, -} from '../../data/index.spec' -import { keyNames } from '../../data/keyData.spec' -import { roleNames } from '../../data/roleData.spec' -import { scopeNames } from '../../data/scopeData.spec' -import { tokenNames } from '../../data/tokenData.spec' -import { userNames } from '../../data/userData.spec' -import { initTestDatabase } from './index.spec' -import Mocha from 'mocha' -import { UninitializedRepositoryError } from '../../../src/types/errors' - -type SuiteName = - | 'create' - | 'write' - | 'save' - | 'find' - | 'findOne' - | 'findOneOrFail' - | 'remove' - | 'format' - | 'additional' -type CustomRecord = Record & { - [k: string]: T -} - -function getRepository(model: { new (): M }): AbstractRepository { - switch (model) { - case ActiveKeyModel: - return activeKeyRepository as any - case KeyModel: - return keyRepository as any - case RoleModel: - return roleRepository as any - case ScopeModel: - return scopeRepository as any - case TokenModel: - return tokenRepository as any - case UserModel: - return userRepository as any - } - - throw new Error(`No repository exists for the given model`) -} - -function getRepositoryClass(model: { - new (): M -}): { new (): AbstractRepository } { - switch (model) { - case ActiveKeyModel: - return ActiveKeyRepository as any - case KeyModel: - return KeyRepository as any - case RoleModel: - return RoleRepository as any - case ScopeModel: - return ScopeRepository as any - case TokenModel: - return TokenRepository as any - case UserModel: - return UserRepository as any - } - - throw new Error(`No repository exists for the given model`) -} - -function getEntityNames(model: { new (): M }): EntityName[] { - switch (model) { - case ActiveKeyModel: - return activeKeyNames as any - case KeyModel: - return keyNames as any - case RoleModel: - return roleNames as any - case ScopeModel: - return scopeNames as any - case TokenModel: - return tokenNames as any - case UserModel: - return userNames as any - } - - throw new Error(`No entity names exist for the given model`) -} - -interface RepositoryTestData { - model: { new (): M } - entityData: PartialTestData - repository: AbstractRepository - validateCreate(model: M, data?: ModelType): boolean - validateWrite(model: M, data: ModelType): boolean - validateFormat(model: M, data: ModelType): boolean - compareModels(firstModel: M, secondModel: M, complete?: boolean): boolean - getFindOptionsWhere(model?: M): FindOptionsWhere -} - -export abstract class AbstractRepositoryTestSuite { - protected model: { new (): M } - protected entityData?: PartialTestData - protected repository: AbstractRepository - protected testSuites?: CustomRecord - protected testData?: TestData - protected repositoryTestData?: RepositoryTestData - - constructor(model: { new (): M }) { - this.model = model - this.repository = getRepository(model) - } - - public async initialize() { - this.testData = await initTestDatabase() - this.entityData = getFromTestData(this.testData, this.model) - - const model = this.model - const entityData = this.entityData - const repository = this.repository - const compareModels = this.compareModels.bind(this) - const getFindOptionsWhere = this.getFindOptionsWhere.bind(this) - const validateCreate = this.validateCreate.bind(this) - const validateFormat = this.validateFormat.bind(this) - const validateWrite = this.validateWrite.bind(this) - - this.repositoryTestData = { - model, - entityData, - repository, - compareModels, - getFindOptionsWhere, - validateCreate, - validateFormat, - validateWrite, - } - - this.testSuites = { - additional: (() => { - const testSuite = new Mocha.Suite('additional') - return testSuite - })(), - create: (() => { - const testSuite = new Mocha.Suite('create') - testSuite.addTest( - new Mocha.Test( - 'should create a model from empty data', - async function () { - const innerModel = await repository.create() - assert(validateCreate(innerModel)) - } - ) - ) - for (const key of getEntityNames(model)) { - testSuite.addTest( - new Mocha.Test( - `should create a model from valid data (${key})`, - async function () { - const innerModel = await repository.create( - entityData[key].request - ) - assert(validateCreate(innerModel, entityData[key].request)) - } - ) - ) - } - testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - for (const key of getEntityNames(model)) { - const unitializedRepository: AbstractRepository = - new (getRepositoryClass(model) as any)() - try { - await unitializedRepository.create( - entityData[key].request - ) - fail() - } catch (error) { - assert(error instanceof UninitializedRepositoryError) - } - } - } - ) - ) - return testSuite - })(), - find: (() => { - const testSuite = new Mocha.Suite('find') - testSuite.addTest( - new Mocha.Test('should find all models', async function () { - const models = await repository.find() - for (const key of getEntityNames(model)) { - assert( - models.find((m) => - compareModels(m, entityData[key].model, false) - ), - `Did not find model for entity data "${key}"` - ) - } - }) - ) - testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - const unitializedRepository: AbstractRepository = - new (getRepositoryClass(model) as any)() - try { - await unitializedRepository.find() - fail() - } catch (error) { - assert(error instanceof UninitializedRepositoryError) - } - } - ) - ) - return testSuite - })(), - findOne: (() => { - const testSuite = new Mocha.Suite('findOne') - for (const key of getEntityNames(model)) { - testSuite.addTest( - new Mocha.Test( - `should find a specific existing model (${key})`, - async function () { - const innerModel = await repository.findOne({ - where: getFindOptionsWhere(entityData[key].model), - }) - assert(innerModel) - assert(compareModels(innerModel, entityData[key].model, false)) - } - ) - ) - } - testSuite.addTest( - new Mocha.Test( - 'should return null when the model does not exist', - async function () { - const innerModel = await repository.findOne({ - where: getFindOptionsWhere(), - }) - assert(innerModel === null) - } - ) - ) - testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - const unitializedRepository: AbstractRepository = - new (getRepositoryClass(model) as any)() - try { - await unitializedRepository.findOne({}) - fail() - } catch (error) { - assert(error instanceof UninitializedRepositoryError) - } - } - ) - ) - return testSuite - })(), - findOneOrFail: (() => { - const testSuite = new Mocha.Suite('findOneOrFail') - for (const key of getEntityNames(model)) { - testSuite.addTest( - new Mocha.Test( - `should find a specific existing model (${key})`, - async function () { - const innerModel = await repository.findOne({ - where: getFindOptionsWhere(entityData[key].model), - }) - assert(innerModel) - assert(compareModels(innerModel, entityData[key].model, false)) - } - ) - ) - } - testSuite.addTest( - new Mocha.Test( - 'should throw a MissingEntityError when the model does not exist', - async function () { - try { - await repository.findOneOrFail({ - where: getFindOptionsWhere(), - }) - fail() - } catch (error) { - assert(error instanceof MissingEntityError) - } - } - ) - ) - testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - const unitializedRepository: AbstractRepository = - new (getRepositoryClass(model) as any)() - try { - await unitializedRepository.findOneOrFail({}) - fail() - } catch (error) { - assert(error instanceof UninitializedRepositoryError) - } - } - ) - ) - return testSuite - })(), - format: (() => { - const testSuite = new Mocha.Suite('format') - for (const key of getEntityNames(model)) { - testSuite.addTest( - new Mocha.Test( - `should correctly format a model (${key})`, - async function () { - const formatted = await repository.format( - entityData[key].model - ) - assert(validateFormat(entityData[key].model, formatted)) - } - ) - ) - } - return testSuite - })(), - remove: (() => { - const testSuite = new Mocha.Suite('remove') - for (const key of getEntityNames(model)) { - testSuite.addTest( - new Mocha.Test( - `should remove a specific existing model (${key})`, - async function () { - const innerModel = await repository.findOne({ - where: getFindOptionsWhere(entityData[key].model), - }) - assert(innerModel) - assert(compareModels(innerModel, entityData[key].model, false)) - await repository.remove(innerModel) - assert( - (await repository.findOne({ - where: getFindOptionsWhere(entityData[key].model), - })) === null - ) - } - ) - ) - } - testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - for (const key of getEntityNames(model)) { - const unitializedRepository: AbstractRepository = - new (getRepositoryClass(model) as any)() - try { - await unitializedRepository.remove( - entityData[key].model - ) - fail() - } catch (error) { - assert(error instanceof UninitializedRepositoryError) - } - } - } - ) - ) - return testSuite - })(), - save: (() => { - const testSuite = new Mocha.Suite('save') - for (const key of getEntityNames(model)) { - testSuite.addTest( - new Mocha.Test( - `should save a valid model (${key})`, - async function () { - const innerModel = await repository.create( - entityData[key].request - ) - assert(validateCreate(innerModel, entityData[key].request)) - const savedModel = await repository.save(innerModel) - assert(compareModels(innerModel, savedModel)) - } - ) - ) - } - testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - for (const key of getEntityNames(model)) { - const unitializedRepository: AbstractRepository = - new (getRepositoryClass(model) as any)() - try { - await unitializedRepository.save( - entityData[key].model - ) - fail() - } catch (error) { - assert(error instanceof UninitializedRepositoryError) - } - } - } - ) - ) - return testSuite - })(), - write: (() => { - const testSuite = new Mocha.Suite('write') - for (const key of getEntityNames(model)) { - testSuite.addTest( - new Mocha.Test( - `should write valid data to a model correctly (${key})`, - async function () { - const innerModel = await repository.create() - assert(validateCreate(innerModel)) - await repository.write(innerModel, entityData[key].request) - assert(validateWrite(innerModel, entityData[key].request)) - } - ) - ) - } - return testSuite - })(), - } - } - - public addTestToSuite( - suiteName: SuiteName, - test: (data: RepositoryTestData) => Mocha.Test - ) { - if (!this.testSuites || !this.repositoryTestData) - throw new Error('Test suite has not been initialized') - this.testSuites[suiteName].addTest(test(this.repositoryTestData)) - } - - public addSuiteToSuite( - suiteName: SuiteName, - suite: (data: RepositoryTestData) => Mocha.Suite - ) { - if (!this.testSuites || !this.repositoryTestData) - throw new Error('Test suite has not been initialized') - this.testSuites[suiteName].addSuite(suite(this.repositoryTestData)) - } - - public addSuite( - suiteName: string, - suite: (data: RepositoryTestData) => Mocha.Suite - ) { - if (!this.testSuites || !this.repositoryTestData) - throw new Error('Test suite has not been initialized') - this.testSuites[suiteName] = suite(this.repositoryTestData) - } - - protected async resetDatabase() { - if (AppDataSource.connected) { - await AppDataSource.teardown() - } - this.testData = await initTestDatabase() - const newEntityData = getFromTestData(this.testData, this.model) - - for (const key in newEntityData) { - (this.entityData as any)[key] = (newEntityData as any)[key] - } - } - - public execute() { - const testSuites = this.testSuites - const testSuite = new Mocha.Suite(`${getModelName(this.model)} Repository Test`) - for (const suite in testSuites) { - // eslint-disable-next-line @typescript-eslint/no-this-alias - const reference = this - testSuites[suite].beforeEach(async function () { - await reference.resetDatabase() - }) - testSuite.addSuite(testSuites[suite]) - } - return testSuite - } - - abstract validateCreate(model: M, data?: ModelType): boolean - abstract validateWrite(model: M, data: ModelType): boolean - abstract validateFormat(model: M, data: ModelType): boolean - abstract compareModels(firstModel: M, secondModel: M, complete?: boolean): boolean - abstract compareFormatted( - first: ModelType, - second: ModelType - ): boolean - abstract getFindOptionsWhere(model?: M): FindOptionsWhere -} diff --git a/services/auth/test/database/repositories/activeKeyRepository.spec.ts b/services/auth/test/database/repositories/activeKeyRepository.spec.ts index 520eeffc..f1976d83 100644 --- a/services/auth/test/database/repositories/activeKeyRepository.spec.ts +++ b/services/auth/test/database/repositories/activeKeyRepository.spec.ts @@ -1,12 +1,27 @@ -import assert from 'assert' -import { FindOptionsWhere } from 'typeorm' +import { AppDataSource } from '../../../src/database/dataSource' import { ActiveKeyModel } from '../../../src/database/model' +import { + ActiveKeyRepository, + activeKeyRepository, +} from '../../../src/database/repositories/activeKeyRepository' import { ActiveKey } from '../../../src/types/types' -import { AbstractRepositoryTestSuite } from './abstractRepository.spec' +import { ActiveKeyName } from '../../data/activeKeyData.spec' +import { initTestDatabase } from './index.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import { FindOptionsWhere } from 'typeorm' + +class ActiveKeyRepositoryTest extends AbstractRepositoryTestSuite< + ActiveKeyName, + ActiveKeyRepository +> { + protected name = 'active keys' as const + protected repository = activeKeyRepository + protected getEntityData = async () => (await initTestDatabase())['active keys'] + protected RepositoryClass = ActiveKeyRepository -class ActiveKeyRepositoryTest extends AbstractRepositoryTestSuite { constructor() { - super(ActiveKeyModel) + super(AppDataSource) } validateCreate(model: ActiveKeyModel, data?: ActiveKey<'request'>): boolean { diff --git a/services/auth/test/database/repositories/index.spec.ts b/services/auth/test/database/repositories/index.spec.ts index d8ffbdda..cf868943 100644 --- a/services/auth/test/database/repositories/index.spec.ts +++ b/services/auth/test/database/repositories/index.spec.ts @@ -1,4 +1,3 @@ -import { DataSourceOptions } from 'typeorm' import { AppDataSource } from '../../../src/database/dataSource' import { ScopeModel, @@ -28,6 +27,7 @@ import { roleRepositoryTestSuite } from './roleRepository.spec' import { scopeRepositoryTestSuite } from './scopeRepository.spec' import { tokenRepositoryTestSuite } from './tokenRepository.spec' import { userRepositoryTestSuite } from './userRepository.spec' +import { DataSourceOptions } from 'typeorm' const repositoryTestSuites = [ activeKeyRepositoryTestSuite, @@ -81,7 +81,7 @@ export async function initTestDatabase(): Promise { } for (const activeKeyName of activeKeyNames) { - await activeKeyRepository.save(testData.activeKeys[activeKeyName].model) + await activeKeyRepository.save(testData['active keys'][activeKeyName].model) } for (const roleName of roleNames) { diff --git a/services/auth/test/database/repositories/keyRepository.spec.ts b/services/auth/test/database/repositories/keyRepository.spec.ts index 635f4421..167eb8b9 100644 --- a/services/auth/test/database/repositories/keyRepository.spec.ts +++ b/services/auth/test/database/repositories/keyRepository.spec.ts @@ -1,12 +1,24 @@ -import assert from 'assert' -import { FindOptionsWhere } from 'typeorm' +import { AppDataSource } from '../../../src/database/dataSource' import { KeyModel } from '../../../src/database/model' -import { AbstractRepositoryTestSuite } from './abstractRepository.spec' +import { + KeyRepository, + keyRepository, +} from '../../../src/database/repositories/keyRepository' import { Key } from '../../../src/types/types' +import { KeyName } from '../../data/keyData.spec' +import { initTestDatabase } from './index.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import { FindOptionsWhere } from 'typeorm' + +class KeyRepositoryTestSuite extends AbstractRepositoryTestSuite { + protected name = 'keys' as const + protected repository = keyRepository + protected getEntityData = async () => (await initTestDatabase())['keys'] + protected RepositoryClass = KeyRepository -class KeyRepositoryTestSuite extends AbstractRepositoryTestSuite { constructor() { - super(KeyModel) + super(AppDataSource) } validateCreate(model: KeyModel, data?: Key<'request'>): boolean { diff --git a/services/auth/test/database/repositories/roleRepository.spec.ts b/services/auth/test/database/repositories/roleRepository.spec.ts index 1a64e8a8..78e2ba13 100644 --- a/services/auth/test/database/repositories/roleRepository.spec.ts +++ b/services/auth/test/database/repositories/roleRepository.spec.ts @@ -1,16 +1,29 @@ -import assert from 'assert' -import { FindOptionsWhere } from 'typeorm' +import { AppDataSource } from '../../../src/database/dataSource' import { RoleModel } from '../../../src/database/model' +import { + roleRepository, + RoleRepository, +} from '../../../src/database/repositories/roleRepository' import { Role } from '../../../src/generated/types' -import { AbstractRepositoryTestSuite } from './abstractRepository.spec' -import Mocha from 'mocha' +import { RoleName, roleNames } from '../../data/roleData.spec' +import { initTestDatabase } from './index.spec' import { scopeRepositoryTestSuite } from './scopeRepository.spec' -import { roleNames } from '../../data/roleData.spec' -import { RoleRepository } from '../../../src/database/repositories/roleRepository' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import Mocha from 'mocha' +import { FindOptionsWhere } from 'typeorm' + +class RoleRepositoryTestSuite extends AbstractRepositoryTestSuite< + RoleName, + RoleRepository +> { + protected name = 'roles' as const + protected repository = roleRepository + protected getEntityData = async () => (await initTestDatabase())['roles'] + protected RepositoryClass = RoleRepository -class RoleRepositoryTestSuite extends AbstractRepositoryTestSuite { constructor() { - super(RoleModel) + super(AppDataSource) } public async initialize(): Promise { diff --git a/services/auth/test/database/repositories/scopeRepository.spec.ts b/services/auth/test/database/repositories/scopeRepository.spec.ts index cae081a1..a2f52e69 100644 --- a/services/auth/test/database/repositories/scopeRepository.spec.ts +++ b/services/auth/test/database/repositories/scopeRepository.spec.ts @@ -1,12 +1,27 @@ -import assert from 'assert' -import { FindOptionsWhere } from 'typeorm' +import { AppDataSource } from '../../../src/database/dataSource' import { ScopeModel } from '../../../src/database/model' +import { + ScopeRepository, + scopeRepository, +} from '../../../src/database/repositories/scopeRepository' import { Scope } from '../../../src/types/types' -import { AbstractRepositoryTestSuite } from './abstractRepository.spec' +import { ScopeName } from '../../data/scopeData.spec' +import { initTestDatabase } from './index.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import { FindOptionsWhere } from 'typeorm' + +class ScopeRepositoryTestSuite extends AbstractRepositoryTestSuite< + ScopeName, + ScopeRepository +> { + protected name = 'scopes' as const + protected repository = scopeRepository + protected getEntityData = async () => (await initTestDatabase())['scopes'] + protected RepositoryClass = ScopeRepository -class ScopeRepositoryTestSuite extends AbstractRepositoryTestSuite { constructor() { - super(ScopeModel) + super(AppDataSource) } validateCreate(model: ScopeModel, data?: Scope<'request'>): boolean { diff --git a/services/auth/test/database/repositories/tokenRepository.spec.ts b/services/auth/test/database/repositories/tokenRepository.spec.ts index c115ec08..7bafd6ee 100644 --- a/services/auth/test/database/repositories/tokenRepository.spec.ts +++ b/services/auth/test/database/repositories/tokenRepository.spec.ts @@ -1,14 +1,28 @@ -import assert from 'assert' -import { FindOptionsWhere } from 'typeorm' +import { AppDataSource } from '../../../src/database/dataSource' import { TokenModel } from '../../../src/database/model' -import { TokenRepository } from '../../../src/database/repositories/tokenRepository' +import { + tokenRepository, + TokenRepository, +} from '../../../src/database/repositories/tokenRepository' import { Token } from '../../../src/types/types' -import { AbstractRepositoryTestSuite } from './abstractRepository.spec' +import { TokenName } from '../../data/tokenData.spec' +import { initTestDatabase } from './index.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' +import { FindOptionsWhere } from 'typeorm' + +class TokenRepositoryTestSuite extends AbstractRepositoryTestSuite< + TokenName, + TokenRepository +> { + protected name = 'tokens' as const + protected repository = tokenRepository + protected getEntityData = async () => (await initTestDatabase())['tokens'] + protected RepositoryClass = TokenRepository -class TokenRepositoryTestSuite extends AbstractRepositoryTestSuite { constructor() { - super(TokenModel) + super(AppDataSource) } public async initialize(): Promise { diff --git a/services/auth/test/database/repositories/userRepository.spec.ts b/services/auth/test/database/repositories/userRepository.spec.ts index db6f3ed3..6a965bfd 100644 --- a/services/auth/test/database/repositories/userRepository.spec.ts +++ b/services/auth/test/database/repositories/userRepository.spec.ts @@ -1,17 +1,30 @@ -import assert from 'assert' -import { compareSync } from 'bcryptjs' -import { FindOptionsWhere } from 'typeorm' +import { AppDataSource } from '../../../src/database/dataSource' import { UserModel } from '../../../src/database/model' -import { UserRepository } from '../../../src/database/repositories/userRepository' +import { + userRepository, + UserRepository, +} from '../../../src/database/repositories/userRepository' import { User, UserInit, UserUpdate } from '../../../src/generated/types' -import { AbstractRepositoryTestSuite } from './abstractRepository.spec' -import Mocha from 'mocha' -import { userNames } from '../../data/userData.spec' import { userUrlFromId } from '../../../src/methods/utils' +import { UserName, userNames } from '../../data/userData.spec' +import { initTestDatabase } from './index.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import { compareSync } from 'bcryptjs' +import Mocha from 'mocha' +import { FindOptionsWhere } from 'typeorm' + +class UserRepositoryTestSuite extends AbstractRepositoryTestSuite< + UserName, + UserRepository +> { + protected name = 'users' as const + protected repository = userRepository + protected getEntityData = async () => (await initTestDatabase())['users'] + protected RepositoryClass = UserRepository -class UserRepositoryTestSuite extends AbstractRepositoryTestSuite { constructor() { - super(UserModel) + super(AppDataSource) } public async initialize(): Promise { diff --git a/services/common/package-lock.json b/services/common/package-lock.json index 0eff0cde..4ae0d718 100644 --- a/services/common/package-lock.json +++ b/services/common/package-lock.json @@ -11,10 +11,15 @@ }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", + "@types/sinon": "^10.0.13", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "eslint": "^8.34.0", + "mocha": "^10.2.0", + "sinon": "^15.0.1", + "typeorm": "^0.3.6", "typescript": "^4.9.4" } }, @@ -718,6 +723,47 @@ "node": ">= 8" } }, + "node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", + "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, + "node_modules/@sqltools/formatter": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", + "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==", + "dev": true + }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.0.0.tgz", @@ -743,6 +789,12 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "node_modules/@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, "node_modules/@types/node": { "version": "18.13.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", @@ -755,6 +807,21 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "node_modules/@types/sinon": { + "version": "10.0.13", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", + "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.52.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", @@ -1174,6 +1241,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/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, + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1195,6 +1271,34 @@ "node": ">=4" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1216,6 +1320,35 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1238,6 +1371,12 @@ "node": ">=8" } }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "node_modules/browserslist": { "version": "4.21.5", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", @@ -1266,6 +1405,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1275,6 +1438,18 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001452", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz", @@ -1305,6 +1480,188 @@ "node": ">=4" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/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==", + "dev": true + }, + "node_modules/cli-highlight/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/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==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -1346,6 +1703,19 @@ "node": ">= 8" } }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "dev": true, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1363,12 +1733,33 @@ } } }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1393,12 +1784,27 @@ "node": ">=6.0.0" } }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.295", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz", "integrity": "sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==", "dev": true }, + "node_modules/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==", + "dev": true + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1820,6 +2226,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -1845,6 +2260,20 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -1854,10 +2283,19 @@ "node": ">=6.9.0" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/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==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -1930,6 +2368,44 @@ "node": ">=4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/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==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -1980,6 +2456,18 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/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, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1989,6 +2477,15 @@ "node": ">=0.10.0" } }, + "node_modules/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2019,6 +2516,33 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2103,6 +2627,12 @@ "node": ">=6" } }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2137,12 +2667,104 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, "node_modules/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 }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/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==", + "dev": true + }, + "node_modules/log-symbols/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2196,77 +2818,77 @@ "node": "*" } }, - "node_modules/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 - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "node_modules/mkdirp": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.3.tgz", + "integrity": "sha512-sjAkg21peAG9HS+Dkx7hlG9Ztx7HLeKnvB3NQRcu/mltCVmvkF0pisbiTSfDVYTT86XEfZrTUosLdZLStquZUw==", "dev": true, - "peer": true, "bin": { - "nanoid": "bin/nanoid.cjs" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, "dependencies": { - "wrappy": "1" + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" } }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/mocha/node_modules/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, - "dependencies": { - "yocto-queue": "^0.1.0" - }, "engines": { "node": ">=10" }, @@ -2274,49 +2896,312 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "dependencies": { - "p-limit": "^3.0.2" + "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" }, "engines": { - "node": ">=10" + "node": "*" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/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==", + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "callsites": "^3.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=6" + "node": "*" } }, - "node_modules/path-exists": { + "node_modules/mocha/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/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 + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/nise": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", + "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/path-key": { @@ -2328,6 +3213,15 @@ "node": ">=8" } }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -2434,6 +3328,33 @@ } ] }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/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==", + "dev": true + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -2446,6 +3367,15 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2503,6 +3433,32 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/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==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -2512,23 +3468,84 @@ "semver": "bin/semver.js" } }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/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, - "dependencies": { - "shebang-regex": "^3.0.0" - }, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/sinon": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.1.tgz", + "integrity": "sha512-PZXKc08f/wcA/BMRGBze2Wmw50CWPiAH3E21EOi4B49vJ616vW4DQh4fQrqsYox2aNR/N3kCqLuB0PwwOucQrg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "10.0.2", + "@sinonjs/samsam": "^7.0.1", + "diff": "^5.0.0", + "nise": "^5.1.2", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/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, "engines": { "node": ">=8" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/sinon/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { "node": ">=8" } @@ -2569,6 +3586,20 @@ "dev": true, "peer": true }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -2611,6 +3642,27 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -2665,6 +3717,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -2677,6 +3738,230 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typeorm": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", + "integrity": "sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==", + "dev": true, + "dependencies": { + "@sqltools/formatter": "^1.2.5", + "app-root-path": "^3.1.0", + "buffer": "^6.0.3", + "chalk": "^4.1.2", + "cli-highlight": "^2.1.11", + "date-fns": "^2.29.3", + "debug": "^4.3.4", + "dotenv": "^16.0.3", + "glob": "^8.1.0", + "js-yaml": "^4.1.0", + "mkdirp": "^2.1.3", + "reflect-metadata": "^0.1.13", + "sha.js": "^2.4.11", + "tslib": "^2.5.0", + "uuid": "^9.0.0", + "xml2js": "^0.4.23", + "yargs": "^17.6.2" + }, + "bin": { + "typeorm": "cli.js", + "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", + "typeorm-ts-node-esm": "cli-ts-node-esm.js" + }, + "engines": { + "node": ">= 12.9.0" + }, + "funding": { + "url": "https://opencollective.com/typeorm" + }, + "peerDependencies": { + "@google-cloud/spanner": "^5.18.0", + "@sap/hana-client": "^2.12.25", + "better-sqlite3": "^7.1.2 || ^8.0.0", + "hdb-pool": "^0.1.6", + "ioredis": "^5.0.4", + "mongodb": "^3.6.0", + "mssql": "^7.3.0", + "mysql2": "^2.2.5 || ^3.0.1", + "oracledb": "^5.1.0", + "pg": "^8.5.1", + "pg-native": "^3.0.0", + "pg-query-stream": "^4.0.0", + "redis": "^3.1.1 || ^4.0.0", + "sql.js": "^1.4.0", + "sqlite3": "^5.0.3", + "ts-node": "^10.7.0", + "typeorm-aurora-data-api-driver": "^2.0.0" + }, + "peerDependenciesMeta": { + "@google-cloud/spanner": { + "optional": true + }, + "@sap/hana-client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "hdb-pool": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mssql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "redis": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "ts-node": { + "optional": true + }, + "typeorm-aurora-data-api-driver": { + "optional": true + } + } + }, + "node_modules/typeorm/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/typeorm/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typeorm/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/typeorm/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/typeorm/node_modules/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==", + "dev": true + }, + "node_modules/typeorm/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/typeorm/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typeorm/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typeorm/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "dev": true + }, "node_modules/typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", @@ -2725,6 +4010,15 @@ "punycode": "^2.1.0" } }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2749,18 +4043,147 @@ "node": ">=0.10.0" } }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/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==", + "dev": true + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/services/common/package.json b/services/common/package.json index f23612e8..883be4e9 100644 --- a/services/common/package.json +++ b/services/common/package.json @@ -23,10 +23,13 @@ }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "eslint": "^8.34.0", + "mocha": "^10.2.0", + "typeorm": "^0.3.6", "typescript": "^4.9.4" } } diff --git a/services/common/src/database/abstractDataSource.ts b/services/common/src/database/abstractDataSource.ts new file mode 100644 index 00000000..2758c234 --- /dev/null +++ b/services/common/src/database/abstractDataSource.ts @@ -0,0 +1,28 @@ +import {DataSource, DataSourceOptions, EntityTarget, ObjectLiteral} from 'typeorm'; + +export abstract class AbstractApplicationDataSource { + private dataSource?: DataSource; + public connected: boolean = false; + + protected abstract initializeRepositories(): void; + + public async initialize(options: DataSourceOptions) { + this.dataSource = new DataSource(options); + await this.dataSource.initialize(); + this.connected = true; + this.initializeRepositories(); + } + + public async teardown() { + if (!this.dataSource?.isInitialized) throw new Error('Data Source has not been initialized!'); + + await this.dataSource.destroy(); + this.connected = false; + } + + public getRepository(target: EntityTarget) { + if (!this.dataSource?.isInitialized) throw new Error('Data Source has not been initialized!'); + + return this.dataSource.getRepository(target); + } +} diff --git a/services/common/src/database/abstractRepository.ts b/services/common/src/database/abstractRepository.ts new file mode 100644 index 00000000..bfa12f6f --- /dev/null +++ b/services/common/src/database/abstractRepository.ts @@ -0,0 +1,99 @@ +import { + FindManyOptions, + FindOneOptions, + FindOptionsRelations, + ObjectLiteral, + Repository, +} from 'typeorm'; + +import {MissingEntityError, UninitializedRepositoryError} from '../errors'; +import {AbstractApplicationDataSource} from './abstractDataSource'; + +/** + * An abstract class for a repository. + * @typeParam M - Type of the model. + * @typeParam RQ - Type of possible request. + * @typeParam RSP - Type of possible response. + */ +export abstract class AbstractRepository< + M extends ObjectLiteral, + RQ extends unknown, + RSP extends unknown, +> { + public name: string; + protected repository?: Repository; + + constructor(name: string) { + this.name = name; + } + + protected throwUninitializedRepositoryError(): never { + throw new UninitializedRepositoryError( + `${this.name} Repository has not been initialized!`, + ); + } + + abstract initialize(AppDataSource: AbstractApplicationDataSource): void; + + public async create(data?: RQ): Promise { + if (!this.repository) this.throwUninitializedRepositoryError(); + const model = this.repository.create(); + if (data === undefined) return model; + await this.write(model, data); + return model; + } + + abstract write(model: M, data: RQ): Promise; + + public async save(model: M): Promise { + if (!this.repository) this.throwUninitializedRepositoryError(); + return await this.repository.save(model); + } + + public async find(options?: FindManyOptions): Promise { + if (!this.repository) this.throwUninitializedRepositoryError(); + const findOptions: FindManyOptions = { + ...(options ?? {}), + relations: options?.relations ?? this.getDefaultFindOptionsRelations(), + }; + return await this.repository.find(findOptions); + } + + public async findOne(options: FindOneOptions): Promise { + if (!this.repository) this.throwUninitializedRepositoryError(); + const findOptions: FindManyOptions = { + ...options, + relations: options?.relations ?? this.getDefaultFindOptionsRelations(), + }; + return await this.repository.findOne(findOptions); + } + + public async findOneOrFail(options: FindOneOptions): Promise { + if (!this.repository) this.throwUninitializedRepositoryError(); + const findOptions: FindOneOptions = { + ...options, + relations: options.relations ?? this.getDefaultFindOptionsRelations(), + }; + const model = await this.repository.findOne(findOptions); + + if (!model) { + throw new MissingEntityError( + `The requested ${this.name} does not exist in the database`, + 404, + ); + } + + return model; + } + + abstract format(model: M): Promise; + + public async remove(model: M): Promise { + if (!this.repository) this.throwUninitializedRepositoryError(); + await this.repository.remove(model); + } + + protected getDefaultFindOptionsRelations(): FindOptionsRelations | undefined { + return undefined; + } +} diff --git a/services/common/src/database/testSuites/abstractRepository.spec.ts b/services/common/src/database/testSuites/abstractRepository.spec.ts new file mode 100644 index 00000000..d1edec9c --- /dev/null +++ b/services/common/src/database/testSuites/abstractRepository.spec.ts @@ -0,0 +1,137 @@ +import Mocha from 'mocha'; + +import {AbstractApplicationDataSource} from '../abstractDataSource'; +import {AbstractRepository} from '../abstractRepository'; +import {testSuiteCreate} from './create.spec'; +import {testSuiteFind} from './find.spec'; +import {testSuiteFindOne} from './findOne.spec'; +import {testSuiteFindOneOrFail} from './findOneOrFail.spec'; +import {testSuiteFormat} from './format.spec'; +import {testSuiteRemove} from './remove.spec'; +import {testSuiteSave} from './save.spec'; +import {CustomRecord, PartialTestData, RepositoryTestData, SuiteName} from './types.spec'; +import {testSuiteWrite} from './write.spec'; + +/** + * An abstract class for a repository. + * @typeParam K - Keys of the EntityData + * @typeParam R - Type of the Repository + */ +export abstract class AbstractRepositoryTestSuite< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +> { + protected entityData?: PartialTestData; + protected testSuites?: CustomRecord; + protected repositoryTestData?: RepositoryTestData; + protected AppDataSource: AbstractApplicationDataSource; + + constructor(AppDataSource: AbstractApplicationDataSource) { + this.AppDataSource = AppDataSource; + } + + protected abstract repository: R; + protected abstract getEntityData: () => Promise>; + protected abstract RepositoryClass: {new (): R}; + + public async initialize() { + this.entityData = await this.getEntityData(); + + this.repositoryTestData = { + entityData: this.entityData, + repository: this.repository, + compareModels: this.compareModels.bind(this), + compareFormatted: this.compareFormatted.bind(this), + getFindOptionsWhere: this.getFindOptionsWhere.bind(this), + validateCreate: this.validateCreate.bind(this), + validateFormat: this.validateFormat.bind(this), + validateWrite: this.validateWrite.bind(this), + RepositoryClass: this.RepositoryClass, + }; + + this.testSuites = { + additional: (() => { + const testSuite = new Mocha.Suite('additional'); + return testSuite; + })(), + create: testSuiteCreate(this.repositoryTestData), + find: testSuiteFind(this.repositoryTestData), + findOne: testSuiteFindOne(this.repositoryTestData), + findOneOrFail: testSuiteFindOneOrFail(this.repositoryTestData), + format: testSuiteFormat(this.repositoryTestData), + remove: testSuiteRemove(this.repositoryTestData), + save: testSuiteSave(this.repositoryTestData), + write: testSuiteWrite(this.repositoryTestData), + }; + } + + public addTestToSuite( + suiteName: SuiteName, + test: (data: RepositoryTestData) => Mocha.Test, + ) { + if (!this.testSuites || !this.repositoryTestData) + throw new Error('Test suite has not been initialized'); + this.testSuites[suiteName].addTest(test(this.repositoryTestData)); + } + + public addSuiteToSuite( + suiteName: SuiteName, + suite: (data: RepositoryTestData) => Mocha.Suite, + ) { + if (!this.testSuites || !this.repositoryTestData) + throw new Error('Test suite has not been initialized'); + this.testSuites[suiteName].addSuite(suite(this.repositoryTestData)); + } + + public addSuite( + suiteName: string, + suite: (data: RepositoryTestData) => Mocha.Suite, + ) { + if (!this.testSuites || !this.repositoryTestData) + throw new Error('Test suite has not been initialized'); + this.testSuites[suiteName] = suite(this.repositoryTestData); + } + + protected async resetDatabase() { + if (this.AppDataSource.connected) { + await this.AppDataSource.teardown(); + } + const newEntityData = await this.getEntityData(); + + for (const key in newEntityData) { + (this.entityData as any)[key] = (newEntityData as any)[key]; + } + } + + public execute() { + const testSuites = this.testSuites; + const testSuite = new Mocha.Suite(`${this.repository.name} Repository Test`); + for (const suite in testSuites) { + const reference = this; + testSuites[suite].beforeEach(async function () { + await reference.resetDatabase(); + }); + testSuite.addSuite(testSuites[suite]); + } + return testSuite; + } + + abstract validateCreate( + ...args: Parameters['validateCreate']> + ): boolean; + abstract validateWrite( + ...args: Parameters['validateWrite']> + ): boolean; + abstract validateFormat( + ...args: Parameters['validateFormat']> + ): boolean; + abstract compareModels( + ...args: Parameters['compareModels']> + ): boolean; + abstract compareFormatted( + ...args: Parameters['compareFormatted']> + ): boolean; + abstract getFindOptionsWhere( + ...args: Parameters['getFindOptionsWhere']> + ): ReturnType['getFindOptionsWhere']>; +} diff --git a/services/common/src/database/testSuites/create.spec.ts b/services/common/src/database/testSuites/create.spec.ts new file mode 100644 index 00000000..b23215e4 --- /dev/null +++ b/services/common/src/database/testSuites/create.spec.ts @@ -0,0 +1,58 @@ +import assert, {fail} from 'assert'; +import Mocha from 'mocha'; + +import {UninitializedRepositoryError} from '../../errors'; +import {AbstractRepository} from '../abstractRepository'; +import {ModelType, RepositoryTestData} from './types.spec'; + +export function testSuiteCreate< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +>(repositoryTestData: RepositoryTestData) { + const testSuite = new Mocha.Suite('create'); + + testSuite.addTest( + new Mocha.Test('should create a model from empty data', async function () { + const model = (await repositoryTestData.repository.create()) as ModelType; + + assert(repositoryTestData.validateCreate(model)); + }), + ); + + for (const key in repositoryTestData.entityData) { + testSuite.addTest( + new Mocha.Test(`should create a model from valid data (${key})`, async function () { + const model = (await repositoryTestData.repository.create( + repositoryTestData.entityData[key].request, + )) as ModelType; + assert( + repositoryTestData.validateCreate( + model, + repositoryTestData.entityData[key].request, + ), + ); + }), + ); + } + + testSuite.addTest( + new Mocha.Test( + 'should throw an UninitializedRepositoryError if the repository has not been initialized', + async function () { + for (const key in repositoryTestData.entityData) { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.create( + repositoryTestData.entityData[key].request, + ); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); + } + } + }, + ), + ); + + return testSuite; +} diff --git a/services/common/src/database/testSuites/find.spec.ts b/services/common/src/database/testSuites/find.spec.ts new file mode 100644 index 00000000..7628ccaa --- /dev/null +++ b/services/common/src/database/testSuites/find.spec.ts @@ -0,0 +1,48 @@ +import assert, {fail} from 'assert'; +import Mocha from 'mocha'; + +import {UninitializedRepositoryError} from '../../errors'; +import {AbstractRepository} from '../abstractRepository'; +import {ModelType, RepositoryTestData} from './types.spec'; + +export function testSuiteFind< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +>(repositoryTestData: RepositoryTestData) { + const testSuite = new Mocha.Suite('find'); + + testSuite.addTest( + new Mocha.Test('should find all models', async function () { + const models = (await repositoryTestData.repository.find()) as ModelType[]; + for (const key in repositoryTestData.entityData) { + assert( + models.find(model => + repositoryTestData.compareModels( + model, + repositoryTestData.entityData[key].model, + false, + ), + ), + `Did not find model for entity data "${key}"`, + ); + } + }), + ); + + testSuite.addTest( + new Mocha.Test( + 'should throw an UninitializedRepositoryError if the repository has not been initialized', + async function () { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.find(); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); + } + }, + ), + ); + + return testSuite; +} diff --git a/services/common/src/database/testSuites/findOne.spec.ts b/services/common/src/database/testSuites/findOne.spec.ts new file mode 100644 index 00000000..c7864434 --- /dev/null +++ b/services/common/src/database/testSuites/findOne.spec.ts @@ -0,0 +1,59 @@ +import assert, {fail} from 'assert'; +import Mocha from 'mocha'; + +import {UninitializedRepositoryError} from '../../errors'; +import {AbstractRepository} from '../abstractRepository'; +import {ModelType, RepositoryTestData} from './types.spec'; + +export function testSuiteFindOne< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +>(repositoryTestData: RepositoryTestData) { + const testSuite = new Mocha.Suite('findOne'); + + for (const key in repositoryTestData.entityData) { + testSuite.addTest( + new Mocha.Test(`should find a specific existing model (${key})`, async function () { + const model = (await repositoryTestData.repository.findOne({ + where: repositoryTestData.getFindOptionsWhere( + repositoryTestData.entityData[key].model, + ), + })) as ModelType; + assert(model); + assert( + repositoryTestData.compareModels( + model, + repositoryTestData.entityData[key].model, + false, + ), + ); + }), + ); + } + + testSuite.addTest( + new Mocha.Test('should return null when the model does not exist', async function () { + const model = await repositoryTestData.repository.findOne({ + where: repositoryTestData.getFindOptionsWhere(), + }); + assert(model === null); + }), + ); + + testSuite.addTest( + new Mocha.Test( + 'should throw an UninitializedRepositoryError if the repository has not been initialized', + async function () { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.findOne({}); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); + } + }, + ), + ); + + return testSuite; +} diff --git a/services/common/src/database/testSuites/findOneOrFail.spec.ts b/services/common/src/database/testSuites/findOneOrFail.spec.ts new file mode 100644 index 00000000..60e03e2f --- /dev/null +++ b/services/common/src/database/testSuites/findOneOrFail.spec.ts @@ -0,0 +1,66 @@ +import assert, {fail} from 'assert'; +import Mocha from 'mocha'; + +import {MissingEntityError, UninitializedRepositoryError} from '../../errors'; +import {AbstractRepository} from '../abstractRepository'; +import {ModelType, RepositoryTestData} from './types.spec'; + +export function testSuiteFindOneOrFail< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +>(repositoryTestData: RepositoryTestData) { + const testSuite = new Mocha.Suite('findOneOrFail'); + + for (const key in repositoryTestData.entityData) { + testSuite.addTest( + new Mocha.Test(`should find a specific existing model (${key})`, async function () { + const model = (await repositoryTestData.repository.findOne({ + where: repositoryTestData.getFindOptionsWhere( + repositoryTestData.entityData[key].model, + ), + })) as ModelType; + assert(model); + assert( + repositoryTestData.compareModels( + model, + repositoryTestData.entityData[key].model, + false, + ), + ); + }), + ); + } + + testSuite.addTest( + new Mocha.Test( + 'should throw a MissingEntityError when the model does not exist', + async function () { + try { + await repositoryTestData.repository.findOneOrFail({ + where: repositoryTestData.getFindOptionsWhere(), + }); + fail(); + } catch (error) { + assert(error instanceof MissingEntityError); + } + }, + ), + ); + + testSuite.addTest( + new Mocha.Test( + 'should throw an UninitializedRepositoryError if the repository has not been initialized', + async function () { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.findOneOrFail({}); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); + } + }, + ), + ); + + return testSuite; +} diff --git a/services/common/src/database/testSuites/format.spec.ts b/services/common/src/database/testSuites/format.spec.ts new file mode 100644 index 00000000..9d4e674a --- /dev/null +++ b/services/common/src/database/testSuites/format.spec.ts @@ -0,0 +1,30 @@ +import assert from 'assert'; +import Mocha from 'mocha'; + +import {AbstractRepository} from '../abstractRepository'; +import {RepositoryTestData, ResponseType} from './types.spec'; + +export function testSuiteFormat< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +>(repositoryTestData: RepositoryTestData) { + const testSuite = new Mocha.Suite('format'); + + for (const key in repositoryTestData.entityData) { + testSuite.addTest( + new Mocha.Test(`should correctly format a model (${key})`, async function () { + const formatted = (await repositoryTestData.repository.format( + repositoryTestData.entityData[key].model, + )) as ResponseType; + assert( + repositoryTestData.validateFormat( + repositoryTestData.entityData[key].model, + formatted, + ), + ); + }), + ); + } + + return testSuite; +} diff --git a/services/common/src/database/testSuites/remove.spec.ts b/services/common/src/database/testSuites/remove.spec.ts new file mode 100644 index 00000000..4c2b1b93 --- /dev/null +++ b/services/common/src/database/testSuites/remove.spec.ts @@ -0,0 +1,63 @@ +import assert, {fail} from 'assert'; +import Mocha from 'mocha'; + +import {UninitializedRepositoryError} from '../../errors'; +import {AbstractRepository} from '../abstractRepository'; +import {ModelType, RepositoryTestData} from './types.spec'; + +export function testSuiteRemove< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +>(repositoryTestData: RepositoryTestData) { + const testSuite = new Mocha.Suite('remove'); + + for (const key in repositoryTestData.entityData) { + testSuite.addTest( + new Mocha.Test( + `should remove a specific existing model (${key})`, + async function () { + const model = (await repositoryTestData.repository.findOne({ + where: repositoryTestData.getFindOptionsWhere( + repositoryTestData.entityData[key].model, + ), + })) as ModelType; + assert(model); + assert( + repositoryTestData.compareModels( + model, + repositoryTestData.entityData[key].model, + false, + ), + ); + await repositoryTestData.repository.remove(model); + assert( + (await repositoryTestData.repository.findOne({ + where: repositoryTestData.getFindOptionsWhere( + repositoryTestData.entityData[key].model, + ), + })) === null, + ); + }, + ), + ); + } + + testSuite.addTest( + new Mocha.Test( + 'should throw an UninitializedRepositoryError if the repository has not been initialized', + async function () { + for (const key in repositoryTestData.entityData) { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.remove(repositoryTestData.entityData[key].model); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); + } + } + }, + ), + ); + + return testSuite; +} diff --git a/services/common/src/database/testSuites/save.spec.ts b/services/common/src/database/testSuites/save.spec.ts new file mode 100644 index 00000000..b7dd2e02 --- /dev/null +++ b/services/common/src/database/testSuites/save.spec.ts @@ -0,0 +1,52 @@ +import assert, {fail} from 'assert'; +import Mocha from 'mocha'; + +import {UninitializedRepositoryError} from '../../errors'; +import {AbstractRepository} from '../abstractRepository'; +import {ModelType, RepositoryTestData} from './types.spec'; + +export function testSuiteSave< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +>(repositoryTestData: RepositoryTestData) { + const testSuite = new Mocha.Suite('save'); + + for (const key in repositoryTestData.entityData) { + testSuite.addTest( + new Mocha.Test(`should save a valid model (${key})`, async function () { + const model = (await repositoryTestData.repository.create( + repositoryTestData.entityData[key].request, + )) as ModelType; + assert( + repositoryTestData.validateCreate( + model, + repositoryTestData.entityData[key].request, + ), + ); + const savedModel = (await repositoryTestData.repository.save( + model, + )) as ModelType; + assert(repositoryTestData.compareModels(model, savedModel)); + }), + ); + } + + testSuite.addTest( + new Mocha.Test( + 'should throw an UninitializedRepositoryError if the repository has not been initialized', + async function () { + for (const key in repositoryTestData.entityData) { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.save(repositoryTestData.entityData[key].model); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); + } + } + }, + ), + ); + + return testSuite; +} diff --git a/services/common/src/database/testSuites/types.spec.ts b/services/common/src/database/testSuites/types.spec.ts new file mode 100644 index 00000000..aaf6db27 --- /dev/null +++ b/services/common/src/database/testSuites/types.spec.ts @@ -0,0 +1,68 @@ +import {FindOptionsWhere} from 'typeorm'; + +import {AbstractRepository} from '../abstractRepository'; + +export type SuiteName = + | 'create' + | 'write' + | 'save' + | 'find' + | 'findOne' + | 'findOneOrFail' + | 'remove' + | 'format' + | 'additional'; + +export type CustomRecord = Record & { + [k: string]: T; +}; + +export interface EntityData> { + model: R extends AbstractRepository ? M : never; + request: R extends AbstractRepository<{}, infer RQ, unknown> ? RQ : never; + response: R extends AbstractRepository<{}, unknown, infer RSP> ? RSP : never; +} + +export type GenericTestData< + D extends [string, string, AbstractRepository<{}, unknown, unknown>][], +> = D extends [ + infer H extends [string, string, AbstractRepository<{}, unknown, unknown>], + ...infer T extends [string, string, AbstractRepository<{}, unknown, unknown>][], +] + ? { + [k in H[0]]: PartialTestData; + } & GenericTestData + : {}; + +export type PartialTestData< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +> = Record>; + +export type ModelType> = + R extends AbstractRepository ? M : never; + +export type RequestType> = + R extends AbstractRepository<{}, infer RQ, unknown> ? RQ : never; + +export type ResponseType> = + R extends AbstractRepository<{}, unknown, infer RSP> ? RSP : never; + +export type RepositoryTestData< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +> = { + entityData: PartialTestData; + repository: R; + validateCreate: (model: ModelType, data?: RequestType) => boolean; + validateWrite(model: ModelType, data: RequestType): boolean; + validateFormat(model: ModelType, data: ResponseType): boolean; + compareModels( + firstModel: ModelType, + secondModel: ModelType, + complete?: boolean, + ): boolean; + compareFormatted(first: ResponseType, second: ResponseType): boolean; + getFindOptionsWhere(model?: ModelType): FindOptionsWhere>; + RepositoryClass: {new (): R}; +}; diff --git a/services/common/src/database/testSuites/write.spec.ts b/services/common/src/database/testSuites/write.spec.ts new file mode 100644 index 00000000..8e1dd614 --- /dev/null +++ b/services/common/src/database/testSuites/write.spec.ts @@ -0,0 +1,36 @@ +import assert from 'assert'; +import Mocha from 'mocha'; + +import {AbstractRepository} from '../abstractRepository'; +import {ModelType, RepositoryTestData} from './types.spec'; + +export function testSuiteWrite< + K extends string, + R extends AbstractRepository<{}, unknown, unknown>, +>(repositoryTestData: RepositoryTestData) { + const testSuite = new Mocha.Suite('write'); + + for (const key in repositoryTestData.entityData) { + testSuite.addTest( + new Mocha.Test( + `should write valid data to a model correctly (${key})`, + async function () { + const model = (await repositoryTestData.repository.create()) as ModelType; + assert(repositoryTestData.validateCreate(model)); + await repositoryTestData.repository.write( + model, + repositoryTestData.entityData[key].request, + ); + assert( + repositoryTestData.validateWrite( + model, + repositoryTestData.entityData[key].request, + ), + ); + }, + ), + ); + } + + return testSuite; +} diff --git a/services/common/src/errors.ts b/services/common/src/errors.ts index 3e5cf201..805e1093 100644 --- a/services/common/src/errors.ts +++ b/services/common/src/errors.ts @@ -1,129 +1,139 @@ export abstract class ErrorWithStatus extends Error { - public status: number | undefined + public status: number | undefined; - constructor(message: string, status?: number) { - super(message) - this.status = status - this.name = "ErrorWithStatus" - } + constructor(message: string, status?: number) { + super(message); + this.status = status; + this.name = 'ErrorWithStatus'; + } } /** * This error class should be used if an entity is not found in the database. */ export class MissingEntityError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'MissingEntityError' - } + constructor(message: string, status?: number) { + super(message, status); + this.name = 'MissingEntityError'; + } } /** * This error class should be used if an object is missing a needed property. */ export class MissingPropertyError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'MissingPropertyError' - } + constructor(message: string, status?: number) { + super(message, status); + this.name = 'MissingPropertyError'; + } } /** * This error class should be used if a device is not related to a peerconnection. */ export class UnrelatedPeerconnectionError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'UnrelatedPeerconnectionError' - } + constructor(message: string, status?: number) { + super(message, status); + this.name = 'UnrelatedPeerconnectionError'; + } } /** * This error class should be used if an object is missing a needed property. */ export class ForbiddenOperationError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'ForbiddenOperationError' - } + constructor(message: string, status?: number) { + super(message, status); + this.name = 'ForbiddenOperationError'; + } } /** * This error class should be used if an object contains an invalid value. */ export class InvalidValueError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'InvalidValueError' - } + constructor(message: string, status?: number) { + super(message, status); + this.name = 'InvalidValueError'; + } } /** * This error class should be used if there is an inconsistency in the database. */ export class InconsistentDatabaseError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'InconsistentDatabaseError' - } + constructor(message: string, status?: number) { + super(message, status); + this.name = 'InconsistentDatabaseError'; + } } /** * This error class should be used if the user attempts an invalid change. */ export class InvalidChangeError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'InvalidChangeError' - } + constructor(message: string, status?: number) { + super(message, status); + this.name = 'InvalidChangeError'; + } } /** * This error class should be used if a required device is not connection. */ export class DeviceNotConnectedError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'DeviceNotConnectedError' - } + constructor(message: string, status?: number) { + super(message, status); + this.name = 'DeviceNotConnectedError'; + } } /** * This error class should be used if an error occurs during JWT verification. */ - export class JWTVerificationError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = "JWTVerificationError" - } +export class JWTVerificationError extends ErrorWithStatus { + constructor(message: string, status?: number) { + super(message, status); + this.name = 'JWTVerificationError'; + } } /** * This error class should be used if the body of a request is malformed. */ - export class MalformedBodyError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = "MalformedBodyError" - } +export class MalformedBodyError extends ErrorWithStatus { + constructor(message: string, status?: number) { + super(message, status); + this.name = 'MalformedBodyError'; + } } /** * This error class should be used if a parameter of a request is missing. */ - export class MissingParameterError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = "MissingParameterError" - } +export class MissingParameterError extends ErrorWithStatus { + constructor(message: string, status?: number) { + super(message, status); + this.name = 'MissingParameterError'; + } } /** * This error class should be used if a parameter of a request is malformed. */ - export class MalformedParameterError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = "MalformedParameterError" - } -} \ No newline at end of file +export class MalformedParameterError extends ErrorWithStatus { + constructor(message: string, status?: number) { + super(message, status); + this.name = 'MalformedParameterError'; + } +} + +/** + * This error class should be used when a repository has not been initialized before use. + */ +export class UninitializedRepositoryError extends ErrorWithStatus { + constructor(message: string) { + super(message, 500); + this.name = 'UninitializedRepositoryError'; + } +} diff --git a/services/common/src/index.ts b/services/common/src/index.ts index 39676b8e..79a47c0d 100644 --- a/services/common/src/index.ts +++ b/services/common/src/index.ts @@ -1,40 +1,51 @@ -import { createRemoteJWKSet, jwtVerify } from 'jose' -import { JWTVerificationError } from "./errors"; -export * from './errors' -import { URL } from 'url'; +import {createRemoteJWKSet, jwtVerify} from 'jose'; +import {URL} from 'url'; -export function JWTVerify(options: { BASE_URL: string, SECURITY_ISSUER: string, SECURITY_AUDIENCE: string }){ - return async (req: any, scopes: string[]) => { - const authorization_header = req.header("Authorization") - if (authorization_header === undefined) { - throw new JWTVerificationError("Authorization header is not set", 401) - } - const bearerTokenResult = /^Bearer (.*)$/.exec(authorization_header); - if (bearerTokenResult === null || bearerTokenResult.length != 2) { - throw new JWTVerificationError("Authorization header is malformed", 401) - } - const jwt = bearerTokenResult[1] - if (!jwt) throw new JWTVerificationError('No JWT provided', 401) - if (!options.SECURITY_ISSUER) - throw new JWTVerificationError('No security issuer specified', 500) - const jwksUri = new URL( - options.BASE_URL.endsWith('/') - ? options.BASE_URL + '.well-known/jwks.json' - : options.BASE_URL + '/.well-known/jwks.json' - ) - const JWKS = createRemoteJWKSet(jwksUri) - const jwtVerifyResult = await jwtVerify(jwt, JWKS, { - issuer: options.SECURITY_ISSUER, - audience: options.SECURITY_AUDIENCE, - }) - const user = jwtVerifyResult.payload - if (!user.scopes || !Array.isArray(user.scopes)) - throw new JWTVerificationError('Payload is malformed', 401) - for (const scope of scopes) { - if ((user.scopes as Array).includes(scope)) { - return user - } - } - throw new JWTVerificationError('Missing Scope: one of ' + scopes, 403) +import {JWTVerificationError} from './errors'; + +export * from './errors'; +export * from './types'; +export * from './database/abstractRepository'; +export * from './database/testSuites/abstractRepository.spec'; +export * from './database/testSuites/types.spec'; +export * from './database/abstractDataSource'; + +export function JWTVerify(options: { + BASE_URL: string; + SECURITY_ISSUER: string; + SECURITY_AUDIENCE: string; +}) { + const jwksUri = new URL( + options.BASE_URL.endsWith('/') + ? options.BASE_URL + '.well-known/jwks.json' + : options.BASE_URL + '/.well-known/jwks.json', + ); + const JWKS = createRemoteJWKSet(jwksUri); + return async (req: any, scopes: string[]) => { + const authorization_header = req.header('Authorization'); + if (authorization_header === undefined) { + throw new JWTVerificationError('Authorization header is not set', 401); + } + const bearerTokenResult = /^Bearer (.*)$/.exec(authorization_header); + if (bearerTokenResult === null || bearerTokenResult.length != 2) { + throw new JWTVerificationError('Authorization header is malformed', 401); + } + const jwt = bearerTokenResult[1]; + if (!jwt) throw new JWTVerificationError('No JWT provided', 401); + if (!options.SECURITY_ISSUER) + throw new JWTVerificationError('No security issuer specified', 500); + const jwtVerifyResult = await jwtVerify(jwt, JWKS, { + issuer: options.SECURITY_ISSUER, + audience: options.SECURITY_AUDIENCE, + }); + const user = jwtVerifyResult.payload; + if (!user.scopes || !Array.isArray(user.scopes)) + throw new JWTVerificationError('Payload is malformed', 401); + for (const scope of scopes) { + if ((user.scopes as Array).includes(scope)) { + return user; + } } -} \ No newline at end of file + throw new JWTVerificationError('Missing Scope: one of ' + scopes, 403); + }; +} diff --git a/services/common/src/types.ts b/services/common/src/types.ts new file mode 100644 index 00000000..24623117 --- /dev/null +++ b/services/common/src/types.ts @@ -0,0 +1,23 @@ +export type ReplaceWith, R> = { + [K in keyof T]: K extends P ? R : T[K]; +}; + +export type RemoveIndex = { + [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K]; +}; + +export type SubstituteType = T extends A + ? B + : T extends {} + ? {[K in keyof T]: SubstituteType} + : T; + +export type Subset = { + [attr in keyof K]?: K[attr] extends object + ? Subset + : K[attr] extends object | null + ? Subset | null + : K[attr] extends object | null | undefined + ? Subset | null | undefined + : K[attr]; +}; From 9af583132179295c161657f0f4f57c91f2b26998 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 20 Mar 2023 11:44:08 +0100 Subject: [PATCH 02/33] Bugfix request and response type generation --- .../src/filters/typescript/resolve.ts | 71 +++++++++++++++++-- .../src/filters/typescript/validation.ts | 4 +- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts b/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts index e7859e68..da0b133b 100644 --- a/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts +++ b/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts @@ -1,6 +1,6 @@ -import { OpenAPIV3_1 } from 'openapi-types' import { formatName, formatOperation } from './format' import { userTypeSchema } from './schemas/userType' +import { OpenAPIV3_1 } from 'openapi-types' /** * This type extends a SchemaObject with the properties 'x-name', 'x-standalone', @@ -339,17 +339,78 @@ export function resolveSchemas( ) as ExtendedSchema[] for (const extendedSchema of _extendedSchemas) { - const readonlyRegex = /"[^"]*?":{[^{}]*?"readOnly":true[^{}]*?},?/gms - const writeonlyRegex = /"[^"]*?":{[^{}]*?"writeOnly":true[^{}]*?},?/gms + const readonlyRegex = /"[^\"]*?":{[^{}]*?"readOnly":true/gms + const writeonlyRegex = /"[^\"]*?":{[^{}]*?"writeOnly":true/gms const stringifiedExtendedSchema = JSON.stringify(extendedSchema) + + const requestRegexMatches = stringifiedExtendedSchema.matchAll(readonlyRegex) + const requestMatches = [] + for (const match of requestRegexMatches) { + let index = match.index ?? 0 + let open = 0 + let started = false + + while (!started || open !== 0) { + if (stringifiedExtendedSchema.at(index) === '{') { + started = true + open++ + } else if (stringifiedExtendedSchema.at(index) === '}') { + open-- + } + index++ + } + + requestMatches.push(stringifiedExtendedSchema.slice(match.index ?? 0, index)) + } + + const responseRegexMatches = stringifiedExtendedSchema.matchAll(writeonlyRegex) + const responseMatches = [] + for (const match of responseRegexMatches) { + let index = match.index ?? 0 + let open = 0 + let started = false + + while (!started || open !== 0) { + if (stringifiedExtendedSchema.at(index) === '{') { + started = true + open++ + } else if (stringifiedExtendedSchema.at(index) === '}') { + open-- + } + index++ + } + + responseMatches.push(stringifiedExtendedSchema.slice(match.index ?? 0, index)) + } + const stringifiedRequestSchema = stringifiedExtendedSchema - .replace(readonlyRegex, '') + .replace( + RegExp( + `(?:${requestMatches + .map((match) => match.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')) + .join('|')})`, + 'gms' + ), + '' + ) + .replace(/,,/g, '') .replace(/,}/g, '}') + .replace(/{,/g, '{') .replace(/"\$ref":"(.*?)"/g, '"$ref":"$1_request"') const stringifiedResponseSchema = stringifiedExtendedSchema - .replace(writeonlyRegex, '') + .replace( + RegExp( + `(?:${responseMatches + .map((match) => match.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')) + .join('|')})`, + 'gms' + ), + '' + ) + .replace(/,,/g, '') .replace(/,}/g, '}') + .replace(/{,/g, '{') .replace(/"\$ref":"(.*?)"/g, '"$ref":"$1_response"') const requestSchema = JSON.parse(stringifiedRequestSchema) as ExtendedSchema diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts b/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts index ebf81868..e0c3c67c 100644 --- a/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts +++ b/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts @@ -1,5 +1,5 @@ import Ajv from 'ajv' -import { format } from 'prettier' +// import { format } from 'prettier' import standaloneCode from 'ajv/dist/standalone' import addFormats from 'ajv-formats' import { ExtendedSchema } from './resolve' @@ -37,5 +37,5 @@ export function validation_filter(schemas: ExtendedSchema[]) { schema['x-name'].slice(1) ] = schema['x-location'] } - return format(standaloneCode(ajv, mapping), { parser: 'babel', tabWidth: 4 }) + return standaloneCode(ajv, mapping) } From 97867cda156f8291aa1efbf34dc96bd2a95d20b6 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 20 Mar 2023 11:48:58 +0100 Subject: [PATCH 03/33] Begin restructuring of Device Service --- services/device/.prettierrc | 3 +- services/device/api/schemas/device.yml | 7 + .../api/schemas/device_cloud_instantiable.yml | 7 +- .../device/api/schemas/device_concrete.yml | 3 +- .../api/schemas/device_edge_instantiable.yml | 7 +- services/device/api/schemas/device_group.yml | 7 +- .../device/api/schemas/device_overview.yml | 2 + .../device/api/schemas/device_reference.yml | 4 +- .../create_peerconnection_message.yml | 1 + .../api/schemas/peerconnection_overview.yml | 8 +- .../device/api/schemas/service_config.yml | 4 + services/device/dist/openapi.json | 77 ++- services/device/package-lock.json | 543 ++++++++++++++++++ services/device/package.json | 6 +- services/device/src/config.ts | 25 + services/device/src/data_source.ts | 38 -- services/device/src/database/dataSource.ts | 12 + .../1670225251577-PeerconnectionStatus.ts | 27 - services/device/src/database/model.ts | 133 +++++ .../src/database/repositories/device.ts | 92 +++ .../repositories/device/concreteDevice.ts | 53 ++ .../repositories/device/deviceGroup.ts | 82 +++ .../repositories/device/deviceOverview.ts | 29 + .../device/instantiableBrowserDevice.ts | 45 ++ .../device/instantiableCloudDevice.ts | 44 ++ .../database/repositories/peerconnection.ts | 77 +++ services/device/src/globals.ts | 10 +- services/device/src/index.ts | 20 +- services/device/src/methods/availability.ts | 129 +++-- services/device/src/methods/callbacks.ts | 73 +-- .../device/src/methods/database/create.ts | 93 --- .../device/src/methods/database/delete.ts | 43 -- services/device/src/methods/database/find.ts | 76 --- .../device/src/methods/database/format.ts | 264 --------- services/device/src/methods/database/save.ts | 36 -- services/device/src/methods/database/write.ts | 275 --------- .../device/src/methods/messageHandling.ts | 29 +- services/device/src/methods/signaling.ts | 75 ++- services/device/src/methods/utils.ts | 59 -- services/device/src/model.ts | 242 -------- services/device/src/operations/devices.ts | 387 ------------- .../devices/device/availability/index.ts | 1 + .../devices/device/availability/post.ts | 51 ++ .../src/operations/devices/device/delete.ts | 26 + .../src/operations/devices/device/get.ts | 26 + .../src/operations/devices/device/index.ts | 7 + .../src/operations/devices/device/patch.ts | 59 ++ .../src/operations/devices/device/post.ts | 89 +++ .../devices/device/signaling/index.ts | 1 + .../devices/device/signaling/post.ts | 69 +++ .../devices/device/websocket/index.ts | 1 + .../devices/device/websocket/post.ts | 39 ++ services/device/src/operations/devices/get.ts | 18 + .../device/src/operations/devices/index.ts | 3 + .../device/src/operations/devices/post.ts | 33 ++ .../device/src/operations/peerconnections.ts | 233 -------- .../src/operations/peerconnections/get.ts | 18 + .../src/operations/peerconnections/index.ts | 3 + .../peerconnections/peerconnection/delete.ts | 52 ++ .../peerconnections/peerconnection/get.ts | 23 + .../peerconnections/peerconnection/index.ts | 2 + .../src/operations/peerconnections/post.ts | 119 ++++ services/device/src/operations/websocket.ts | 34 +- services/device/src/types/device.ts | 24 + services/device/src/types/errors.ts | 101 ---- services/device/src/types/helper.ts | 69 --- 66 files changed, 2122 insertions(+), 2126 deletions(-) create mode 100644 services/device/api/schemas/device.yml delete mode 100644 services/device/src/data_source.ts create mode 100644 services/device/src/database/dataSource.ts delete mode 100644 services/device/src/database/migrations/1670225251577-PeerconnectionStatus.ts create mode 100644 services/device/src/database/model.ts create mode 100644 services/device/src/database/repositories/device.ts create mode 100644 services/device/src/database/repositories/device/concreteDevice.ts create mode 100644 services/device/src/database/repositories/device/deviceGroup.ts create mode 100644 services/device/src/database/repositories/device/deviceOverview.ts create mode 100644 services/device/src/database/repositories/device/instantiableBrowserDevice.ts create mode 100644 services/device/src/database/repositories/device/instantiableCloudDevice.ts create mode 100644 services/device/src/database/repositories/peerconnection.ts delete mode 100644 services/device/src/methods/database/create.ts delete mode 100644 services/device/src/methods/database/delete.ts delete mode 100644 services/device/src/methods/database/find.ts delete mode 100644 services/device/src/methods/database/format.ts delete mode 100644 services/device/src/methods/database/save.ts delete mode 100644 services/device/src/methods/database/write.ts delete mode 100644 services/device/src/model.ts delete mode 100644 services/device/src/operations/devices.ts create mode 100644 services/device/src/operations/devices/device/availability/index.ts create mode 100644 services/device/src/operations/devices/device/availability/post.ts create mode 100644 services/device/src/operations/devices/device/delete.ts create mode 100644 services/device/src/operations/devices/device/get.ts create mode 100644 services/device/src/operations/devices/device/index.ts create mode 100644 services/device/src/operations/devices/device/patch.ts create mode 100644 services/device/src/operations/devices/device/post.ts create mode 100644 services/device/src/operations/devices/device/signaling/index.ts create mode 100644 services/device/src/operations/devices/device/signaling/post.ts create mode 100644 services/device/src/operations/devices/device/websocket/index.ts create mode 100644 services/device/src/operations/devices/device/websocket/post.ts create mode 100644 services/device/src/operations/devices/get.ts create mode 100644 services/device/src/operations/devices/index.ts create mode 100644 services/device/src/operations/devices/post.ts delete mode 100644 services/device/src/operations/peerconnections.ts create mode 100644 services/device/src/operations/peerconnections/get.ts create mode 100644 services/device/src/operations/peerconnections/index.ts create mode 100644 services/device/src/operations/peerconnections/peerconnection/delete.ts create mode 100644 services/device/src/operations/peerconnections/peerconnection/get.ts create mode 100644 services/device/src/operations/peerconnections/peerconnection/index.ts create mode 100644 services/device/src/operations/peerconnections/post.ts create mode 100644 services/device/src/types/device.ts delete mode 100644 services/device/src/types/errors.ts delete mode 100644 services/device/src/types/helper.ts diff --git a/services/device/.prettierrc b/services/device/.prettierrc index c3652cb6..aebbafb7 100644 --- a/services/device/.prettierrc +++ b/services/device/.prettierrc @@ -4,5 +4,6 @@ "tabWidth": 4, "semi": false, "singleQuote": true, - "printWidth": 90 + "printWidth": 90, + "importOrderParserPlugins": ["typescript", "decorators-legacy"] } \ No newline at end of file diff --git a/services/device/api/schemas/device.yml b/services/device/api/schemas/device.yml new file mode 100644 index 00000000..da53863b --- /dev/null +++ b/services/device/api/schemas/device.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Device +oneOf: + - $ref: ./device_cloud_instantiable.yml + - $ref: ./device_concrete.yml + - $ref: ./device_edge_instantiable.yml + - $ref: ./device_group.yml \ No newline at end of file diff --git a/services/device/api/schemas/device_cloud_instantiable.yml b/services/device/api/schemas/device_cloud_instantiable.yml index e177c33a..ebdcc9e4 100644 --- a/services/device/api/schemas/device_cloud_instantiable.yml +++ b/services/device/api/schemas/device_cloud_instantiable.yml @@ -6,7 +6,12 @@ allOf: properties: type: const: cloud instantiable - instantiate_url: + instantiateUrl: type: string format: uri + services: + type: array + items: + type: object + additionalProperties: true x-typeguard: true diff --git a/services/device/api/schemas/device_concrete.yml b/services/device/api/schemas/device_concrete.yml index d757f6c8..5dcbce2c 100644 --- a/services/device/api/schemas/device_concrete.yml +++ b/services/device/api/schemas/device_concrete.yml @@ -10,9 +10,10 @@ allOf: description: | If true, the device is connected to the service and can be used. type: boolean - #readOnly: true + readOnly: true announcedAvailability: $ref: "../schemas/availability.yml" + readOnly: true experiment: type: string format: uri diff --git a/services/device/api/schemas/device_edge_instantiable.yml b/services/device/api/schemas/device_edge_instantiable.yml index 5b2f5b25..3cf5d323 100644 --- a/services/device/api/schemas/device_edge_instantiable.yml +++ b/services/device/api/schemas/device_edge_instantiable.yml @@ -6,7 +6,12 @@ allOf: properties: type: const: edge instantiable - code_url: + codeUrl: type: string format: uri + services: + type: array + items: + type: object + additionalProperties: true x-typeguard: true diff --git a/services/device/api/schemas/device_group.yml b/services/device/api/schemas/device_group.yml index a2531eba..de61e320 100644 --- a/services/device/api/schemas/device_group.yml +++ b/services/device/api/schemas/device_group.yml @@ -9,10 +9,5 @@ allOf: devices: type: array items: - type: object - properties: - url: - type: string - description: URL of the device - format: uri + $ref: ./device_reference.yml x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/device_overview.yml b/services/device/api/schemas/device_overview.yml index 4753b233..e8099993 100644 --- a/services/device/api/schemas/device_overview.yml +++ b/services/device/api/schemas/device_overview.yml @@ -25,4 +25,6 @@ properties: type: string format: uri readOnly: true +required: + - url x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/device_reference.yml b/services/device/api/schemas/device_reference.yml index 7fa5e1f8..e45cd2ea 100644 --- a/services/device/api/schemas/device_reference.yml +++ b/services/device/api/schemas/device_reference.yml @@ -5,4 +5,6 @@ properties: url: type: string description: URL of the device - format: uri \ No newline at end of file + format: uri +required: + - url \ No newline at end of file diff --git a/services/device/api/schemas/messages/create_peerconnection_message.yml b/services/device/api/schemas/messages/create_peerconnection_message.yml index 5d59204e..7f329808 100644 --- a/services/device/api/schemas/messages/create_peerconnection_message.yml +++ b/services/device/api/schemas/messages/create_peerconnection_message.yml @@ -11,6 +11,7 @@ allOf: enum: - webrtc - websocket + - local connectionUrl: type: string format: uri diff --git a/services/device/api/schemas/peerconnection_overview.yml b/services/device/api/schemas/peerconnection_overview.yml index a077eca2..8929bf91 100644 --- a/services/device/api/schemas/peerconnection_overview.yml +++ b/services/device/api/schemas/peerconnection_overview.yml @@ -12,4 +12,10 @@ properties: minItems: 2 maxItems: 2 items: - $ref: "./device_reference.yml" \ No newline at end of file + $ref: "./device_reference.yml" + type: + type: string + description: Type of the peerconnection + enum: + - local + - webrtc \ No newline at end of file diff --git a/services/device/api/schemas/service_config.yml b/services/device/api/schemas/service_config.yml index 1dc6eef7..1add2d3b 100644 --- a/services/device/api/schemas/service_config.yml +++ b/services/device/api/schemas/service_config.yml @@ -9,4 +9,8 @@ properties: type: string remoteServiceId: type: string +required: + - serviceType + - serviceId + - remoteServiceId additionalProperties: true \ No newline at end of file diff --git a/services/device/dist/openapi.json b/services/device/dist/openapi.json index a6409f7c..7ddf09f3 100644 --- a/services/device/dist/openapi.json +++ b/services/device/dist/openapi.json @@ -76,6 +76,9 @@ "readOnly": true } }, + "required": [ + "url" + ], "x-typeguard": true }, "time_slot": { @@ -114,10 +117,12 @@ }, "connected": { "description": "If true, the device is connected to the service and can be used.\n", - "type": "boolean" + "type": "boolean", + "readOnly": true }, "announcedAvailability": { - "$ref": "#/components/schemas/availability" + "$ref": "#/components/schemas/availability", + "readOnly": true }, "experiment": { "type": "string", @@ -177,6 +182,20 @@ } ] }, + "device_reference": { + "title": "Device Reference", + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL of the device", + "format": "uri" + } + }, + "required": [ + "url" + ] + }, "device_group": { "title": "Device Group", "allOf": [ @@ -192,14 +211,7 @@ "devices": { "type": "array", "items": { - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "URL of the device", - "format": "uri" - } - } + "$ref": "#/components/schemas/device_reference" } } } @@ -219,9 +231,16 @@ "type": { "const": "cloud instantiable" }, - "instantiate_url": { + "instantiateUrl": { "type": "string", "format": "uri" + }, + "services": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } } } } @@ -240,9 +259,16 @@ "type": { "const": "edge instantiable" }, - "code_url": { + "codeUrl": { "type": "string", "format": "uri" + }, + "services": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } } } } @@ -302,6 +328,11 @@ "type": "string" } }, + "required": [ + "serviceType", + "serviceId", + "remoteServiceId" + ], "additionalProperties": true }, "create_peerconnection_message": { @@ -320,7 +351,8 @@ "type": "string", "enum": [ "webrtc", - "websocket" + "websocket", + "local" ] }, "connectionUrl": { @@ -422,17 +454,6 @@ ], "x-typeguard": true }, - "device_reference": { - "title": "Device Reference", - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "URL of the device", - "format": "uri" - } - } - }, "peerconnection_overview": { "title": "Peerconnection Overview", "type": "object", @@ -450,6 +471,14 @@ "items": { "$ref": "#/components/schemas/device_reference" } + }, + "type": { + "type": "string", + "description": "Type of the peerconnection", + "enum": [ + "local", + "webrtc" + ] } } }, diff --git a/services/device/package-lock.json b/services/device/package-lock.json index 8c0aea9c..2198db63 100644 --- a/services/device/package-lock.json +++ b/services/device/package-lock.json @@ -15,6 +15,7 @@ "jose": "^4.10.0", "mysql": "^2.18.1", "node-fetch": "^2.6.7", + "queue": "^6.0.2", "sqlite3": "^5.0.8", "typeorm": "^0.3.6", "ws": "^8.8.0" @@ -35,6 +36,7 @@ "@typescript-eslint/parser": "^5.51.0", "env-cmd": "^10.1.0", "eslint": "^8.34.0", + "mocha": "^10.2.0", "nodemon": "^2.0.19", "prettier": "^2.7.1", "ts-node": "^10.9.1", @@ -1695,6 +1697,15 @@ } } }, + "node_modules/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, + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1895,6 +1906,33 @@ "node": ">=8" } }, + "node_modules/brfs": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", + "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", + "dev": true, + "dependencies": { + "quote-stream": "^1.0.1", + "resolve": "^1.1.5", + "static-module": "^2.2.0", + "through2": "^2.0.0" + }, + "bin": { + "brfs": "bin/cmd.js" + } + }, + "node_modules/browser-or-node": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.3.0.tgz", + "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==", + "dev": true + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "node_modules/browserslist": { "version": "4.21.5", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", @@ -2022,6 +2060,18 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001452", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz", @@ -2376,6 +2426,18 @@ } } }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3103,6 +3165,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -3330,6 +3401,15 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -3572,6 +3652,48 @@ "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "dev": true + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3688,6 +3810,92 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/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==", + "dev": true + }, + "node_modules/log-symbols/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3965,6 +4173,218 @@ "node": ">=10" } }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/mocha/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/mocha/node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4566,6 +4986,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "dependencies": { + "inherits": "~2.0.3" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4586,6 +5014,85 @@ } ] }, + "node_modules/quicktype-core": { + "version": "6.1.12", + "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-6.1.12.tgz", + "integrity": "sha512-pBV0VbYZEKIG49xaKGHCat6zlUbg1w15fDf3rnbV2IbG3Ec3T7e46V/dIgL+OGWFphjEZ6n7dcWZiogOk9Adtg==", + "dev": true, + "dependencies": { + "@mark.probst/unicode-properties": "~1.1.0", + "browser-or-node": "^1.2.1", + "collection-utils": "^1.0.1", + "is-url": "^1.2.4", + "isomorphic-fetch": "^2.2.1", + "js-base64": "^2.4.3", + "pako": "^1.0.6", + "pluralize": "^7.0.0", + "readable-stream": "2.3.0", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^1.5.0" + } + }, + "node_modules/quicktype-core/node_modules/process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha512-yN0WQmuCX63LP/TMvAg31nvT6m4vDqJEiiv2CAZqWOGNWutc9DfDk1NPYYmKUFmaVM2UwDowH4u5AHWYP/jxKw==", + "dev": true + }, + "node_modules/quicktype-core/node_modules/readable-stream": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.0.tgz", + "integrity": "sha512-c7KMXGd4b48nN3OJ1U9qOsn6pXNzf6kLd3kdZCkg2sxAcoiufInqF0XckwEnlrcwuaYwonlNK8GQUIOC/WC7sg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.0", + "string_decoder": "~1.0.0", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/quicktype-core/node_modules/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==", + "dev": true + }, + "node_modules/quicktype-core/node_modules/string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/quote-stream": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", + "integrity": "sha512-kKr2uQ2AokadPjvTyKJQad9xELbZwYzWlNfI3Uz2j/ib5u6H9lDP7fUUR//rMycd0gv4Z5P1qXMfXR8YpIxrjQ==", + "dev": true, + "dependencies": { + "buffer-equal": "0.0.1", + "minimist": "^1.1.3", + "through2": "^2.0.0" + }, + "bin": { + "quote-stream": "bin/cmd.js" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -4815,6 +5322,15 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -5714,6 +6230,18 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5844,6 +6372,21 @@ "node": ">=12" } }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/services/device/package.json b/services/device/package.json index 9c6746e0..f4371f61 100644 --- a/services/device/package.json +++ b/services/device/package.json @@ -39,7 +39,8 @@ "nodemon": "^2.0.19", "prettier": "^2.7.1", "ts-node": "^10.9.1", - "typescript": "^4.7.4" + "typescript": "^4.7.4", + "mocha": "^10.2.0" }, "dependencies": { "@cross-lab-project/api-client": "file:../../clients/api/js", @@ -50,8 +51,9 @@ "jose": "^4.10.0", "mysql": "^2.18.1", "node-fetch": "^2.6.7", + "queue": "^6.0.2", "sqlite3": "^5.0.8", "typeorm": "^0.3.6", "ws": "^8.8.0" } -} +} \ No newline at end of file diff --git a/services/device/src/config.ts b/services/device/src/config.ts index ba0fb6ab..352a5d0b 100644 --- a/services/device/src/config.ts +++ b/services/device/src/config.ts @@ -1,4 +1,14 @@ +import { + DeviceOverviewModel, + ConcreteDeviceModel, + InstantiableDeviceOverviewModel, + InstantiableCloudDeviceModel, + InstantiableBrowserDeviceModel, + DeviceGroupModel, + PeerconnectionModel, +} from './database/model' import { exit } from 'process' +import { DataSourceOptions } from 'typeorm' function die(reason: string): string { console.error(reason) @@ -19,3 +29,18 @@ export const config = { process.env.SECURITY_AUDIENCE ?? die('the environment variable SECURITY_AUDIENCE is not defined!'), } + +export const dataSourceConfig: DataSourceOptions = { + type: 'sqlite', + database: 'db/device.db', + synchronize: true, + entities: [ + DeviceOverviewModel, + ConcreteDeviceModel, + InstantiableDeviceOverviewModel, + InstantiableCloudDeviceModel, + InstantiableBrowserDeviceModel, + DeviceGroupModel, + PeerconnectionModel, + ], +} diff --git a/services/device/src/data_source.ts b/services/device/src/data_source.ts deleted file mode 100644 index 03679bff..00000000 --- a/services/device/src/data_source.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { DataSource } from 'typeorm' -import { PeerconnectionStatus1670225251577 } from './database/migrations/1670225251577-PeerconnectionStatus' -import { - DeviceOverviewModel, - ConcreteDeviceModel, - DeviceGroupModel, - AvailabilityRuleModel, - DeviceReferenceModel, - PeerconnectionModel, - TimeSlotModel, - ServiceConfigModel, - InstantiableCloudDeviceModel, - InstantiableBrowserDeviceModel, - ServiceModel, - InstantiableDeviceOverviewModel, -} from './model' - -export const AppDataSource = new DataSource({ - type: 'sqlite', - database: 'db/device.db', - synchronize: true, - entities: [ - DeviceOverviewModel, - ConcreteDeviceModel, - InstantiableDeviceOverviewModel, - InstantiableCloudDeviceModel, - InstantiableBrowserDeviceModel, - DeviceGroupModel, - AvailabilityRuleModel, - ServiceConfigModel, - DeviceReferenceModel, - PeerconnectionModel, - TimeSlotModel, - ServiceModel, - ], - migrations: [PeerconnectionStatus1670225251577], - //migrationsRun: true -}) diff --git a/services/device/src/database/dataSource.ts b/services/device/src/database/dataSource.ts new file mode 100644 index 00000000..4830da74 --- /dev/null +++ b/services/device/src/database/dataSource.ts @@ -0,0 +1,12 @@ +import { deviceRepository } from './repositories/device' +import { peerconnectionRepository } from './repositories/peerconnection' +import { AbstractApplicationDataSource } from '@crosslab/service-common' + +class ApplicationDataSource extends AbstractApplicationDataSource { + protected initializeRepositories(): void { + deviceRepository.initialize(this) + peerconnectionRepository.initialize(this) + } +} + +export const AppDataSource = new ApplicationDataSource() diff --git a/services/device/src/database/migrations/1670225251577-PeerconnectionStatus.ts b/services/device/src/database/migrations/1670225251577-PeerconnectionStatus.ts deleted file mode 100644 index c74b7cd4..00000000 --- a/services/device/src/database/migrations/1670225251577-PeerconnectionStatus.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from "typeorm" - -export class PeerconnectionStatus1670225251577 implements MigrationInterface { - async up(queryRunner: QueryRunner): Promise { - await queryRunner.addColumn("Peerconnection", new TableColumn({ - name: "status", - type: "text", - enum: ['waiting-for-devices', 'connected', 'failed', 'closed'], - isNullable: true - })) - - queryRunner.query( - `UPDATE Peerconnection SET status='closed'` - ) - - await queryRunner.changeColumn("Peerconnection", "status", new TableColumn({ - name: "status", - type: "text", - enum: ['waiting-for-devices', 'connected', 'failed', 'closed'], - isNullable: false - })) - } - - async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropColumn("Peerconnection", "status") - } -} diff --git a/services/device/src/database/model.ts b/services/device/src/database/model.ts new file mode 100644 index 00000000..d72c101a --- /dev/null +++ b/services/device/src/database/model.ts @@ -0,0 +1,133 @@ +import { + AvailabilityRule, + DeviceReference, + Peerconnection, + TimeSlot, +} from '../generated/types' +import { + Column, + Entity, + PrimaryGeneratedColumn, + DeleteDateColumn, + OneToMany, + TableInheritance, + ChildEntity, + ManyToOne, +} from 'typeorm' + +@Entity({ name: 'Device' }) +@TableInheritance({ + column: { + type: 'varchar', + name: 'type', + enum: ['device', 'group', 'cloud instantiable', 'edge instantiable'], + }, +}) +export abstract class DeviceOverviewModel { + @PrimaryGeneratedColumn('uuid') + uuid!: string + @Column() + name?: string + @Column({ nullable: true }) + description?: string + @Column() + type!: 'device' | 'group' | 'cloud instantiable' | 'edge instantiable' + @Column() + owner?: string + @DeleteDateColumn() + deletedAt?: Date +} + +@ChildEntity() +export abstract class InstantiableDeviceOverviewModel extends DeviceOverviewModel { + @OneToMany(() => ConcreteDeviceModel, (concreteDevice) => concreteDevice.instanceOf, { + onDelete: 'CASCADE', + cascade: true, + }) + instances?: ConcreteDeviceModel[] +} + +@ChildEntity('device') +export class ConcreteDeviceModel extends DeviceOverviewModel { + @Column() + type!: 'device' + @Column() + connected?: boolean + @Column('simple-json') + announcedAvailability?: Required[] + @Column('simple-json') + availabilityRules?: AvailabilityRule[] + @Column() + experiment?: string + @Column() + token?: string + @Column('simple-json') + services?: { [k: string]: any }[] + @ManyToOne( + () => InstantiableDeviceOverviewModel, + (instantiableDevice) => instantiableDevice.instances + ) + instanceOf?: InstantiableDeviceOverviewModel +} + +@ChildEntity('group') +export class DeviceGroupModel extends DeviceOverviewModel { + @Column() + type!: 'group' + @Column('simple-json') + devices?: DeviceReference[] +} + +@ChildEntity('cloud instantiable') +export class InstantiableCloudDeviceModel extends InstantiableDeviceOverviewModel { + @Column() + type!: 'cloud instantiable' + @Column() + instantiateUrl?: string + @Column('simple-json') + services?: { [k: string]: any }[] +} + +@ChildEntity('edge instantiable') +export class InstantiableBrowserDeviceModel extends InstantiableDeviceOverviewModel { + @Column() + type!: 'edge instantiable' + @Column() + codeUrl?: string + @Column('simple-json') + services?: { [k: string]: any }[] +} + +@Entity({ name: 'Peerconnection' }) +export abstract class PeerconnectionModel { + @PrimaryGeneratedColumn('uuid') + uuid!: string + @Column() + type?: 'local' | 'webrtc' + @Column() + status!: 'waiting-for-devices' | 'connected' | 'failed' | 'closed' + @Column('simple-json') + deviceA!: NonNullable[number] & { + url: string + config?: { + services?: { + serviceType: string + serviceId: string + remoteServiceId: string + }[] + } + } + @Column('simple-json') + deviceB!: NonNullable[number] & { + url: string + config?: { + services?: { + serviceType: string + serviceId: string + remoteServiceId: string + }[] + } + } + @DeleteDateColumn() + deletedAt?: Date +} diff --git a/services/device/src/database/repositories/device.ts b/services/device/src/database/repositories/device.ts new file mode 100644 index 00000000..3c8525a7 --- /dev/null +++ b/services/device/src/database/repositories/device.ts @@ -0,0 +1,92 @@ +import { + DeviceOverview, + isConcreteDevice, + isDeviceGroup, + isInstantiableBrowserDevice, + isInstantiableCloudDevice, +} from '../../generated/types' +import { Device, DeviceModel } from '../../types/device' +import { DeviceOverviewModel } from '../model' +import { concreteDeviceRepository } from './device/concreteDevice' +import { deviceGroupRepository } from './device/deviceGroup' +import { DeviceOverviewRepository } from './device/deviceOverview' +import { instantiableBrowserDeviceRepository } from './device/instantiableBrowserDevice' +import { instantiableCloudDeviceRepository } from './device/instantiableCloudDevice' +import { + AbstractApplicationDataSource, + AbstractRepository, + InvalidValueError, +} from '@crosslab/service-common' + +export class DeviceRepository extends AbstractRepository< + DeviceModel, + Device<'request'>, + Device<'response'> +> { + constructor() { + super('Device') + } + + initialize(AppDataSource: AbstractApplicationDataSource): void { + this.repository = AppDataSource.getRepository(DeviceOverviewModel) + } + + async write(model: DeviceModel, data: Device<'request'>): Promise { + switch (model.type) { + case 'cloud instantiable': + if (!isInstantiableCloudDevice(data)) { + throw new InvalidValueError( + `Provided data cannot be used to update the given device`, + 400 + ) + } + return await instantiableCloudDeviceRepository.write(model, data) + case 'device': + if (!isConcreteDevice(data)) { + throw new InvalidValueError( + `Provided data cannot be used to update the given device`, + 400 + ) + } + return await concreteDeviceRepository.write(model, data) + case 'edge instantiable': + if (!isInstantiableBrowserDevice(data)) { + throw new InvalidValueError( + `Provided data cannot be used to update the given device`, + 400 + ) + } + return await instantiableBrowserDeviceRepository.write(model, data) + case 'group': + if (!isDeviceGroup(data)) { + throw new InvalidValueError( + `Provided data cannot be used to update the given device`, + 400 + ) + } + return await deviceGroupRepository.write(model, data) + } + } + + async format( + model: DeviceModel, + options?: { flatGroup?: boolean } + ): Promise> { + switch (model.type) { + case 'cloud instantiable': + return await instantiableCloudDeviceRepository.format(model) + case 'device': + return await concreteDeviceRepository.format(model) + case 'edge instantiable': + return await instantiableBrowserDeviceRepository.format(model) + case 'group': + return await deviceGroupRepository.format(model, options?.flatGroup) + } + } + + async formatOverview(model: DeviceModel): Promise> { + return await DeviceOverviewRepository.format(model) + } +} + +export const deviceRepository = new DeviceRepository() diff --git a/services/device/src/database/repositories/device/concreteDevice.ts b/services/device/src/database/repositories/device/concreteDevice.ts new file mode 100644 index 00000000..48b8c58b --- /dev/null +++ b/services/device/src/database/repositories/device/concreteDevice.ts @@ -0,0 +1,53 @@ +import { ConcreteDevice } from '../../../generated/types' +import { ConcreteDeviceModel } from '../../model' +import { DeviceOverviewRepository } from './deviceOverview' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' + +export class ConcreteDeviceRepository extends AbstractRepository< + ConcreteDeviceModel, + ConcreteDevice<'request'>, + ConcreteDevice<'response'> +> { + constructor() { + super('Concrete Device') + } + + initialize(AppDataSource: AbstractApplicationDataSource): void { + this.repository = AppDataSource.getRepository(ConcreteDeviceModel) + } + + async write( + model: ConcreteDeviceModel, + data: ConcreteDevice<'request'> + ): Promise { + await DeviceOverviewRepository.write(model, data) + + if (data.experiment) model.experiment = data.experiment + if (data.services) model.services = data.services + } + + async format(model: ConcreteDeviceModel): Promise> { + return { + ...(await DeviceOverviewRepository.format(model)), + type: 'device', + announcedAvailability: model.announcedAvailability + ? model.announcedAvailability.map((timeSlot) => { + return { + start: new Date(timeSlot.start).toISOString(), + end: new Date(timeSlot.end).toISOString(), + } + }) + : undefined, + connected: model.connected !== undefined ? model.connected : undefined, + experiment: model.experiment ? model.experiment : undefined, + services: model.services + ? model.services.map((service) => JSON.parse(service.description)) + : undefined, + } + } +} + +export const concreteDeviceRepository = new ConcreteDeviceRepository() diff --git a/services/device/src/database/repositories/device/deviceGroup.ts b/services/device/src/database/repositories/device/deviceGroup.ts new file mode 100644 index 00000000..1c16beed --- /dev/null +++ b/services/device/src/database/repositories/device/deviceGroup.ts @@ -0,0 +1,82 @@ +import { DeviceGroup, DeviceReference } from '../../../generated/types' +import { apiClient } from '../../../globals' +import { Device } from '../../../types/device' +import { DeviceGroupModel } from '../../model' +import { DeviceOverviewRepository } from './deviceOverview' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' + +export class DeviceGroupRepository extends AbstractRepository< + DeviceGroupModel, + DeviceGroup<'request'>, + DeviceGroup<'response'> +> { + constructor() { + super('Device Group') + } + + initialize(AppDataSource: AbstractApplicationDataSource): void { + this.repository = AppDataSource.getRepository(DeviceGroupModel) + } + + async write(model: DeviceGroupModel, data: DeviceGroup<'request'>): Promise { + await DeviceOverviewRepository.write(model, data) + + model.devices = data.devices + } + + async format( + model: DeviceGroupModel, + flatGroup?: boolean + ): Promise> { + const devices: Device[] = await this.resolveDeviceReferences( + model.devices ?? [], + flatGroup + ) + + return { + ...(await DeviceOverviewRepository.format(model)), + type: 'group', + devices: devices, + } + } + + private async resolveDeviceReferences( + deviceReferences: DeviceReference[], + flatGroup?: boolean + ): Promise { + const devices: Device[] = [] + + for (const deviceReference of deviceReferences) { + const device = await this.resolveDeviceReference(deviceReference, flatGroup) + + if (!device) continue + + if (device.type === 'group' && flatGroup) { + devices.push(...(device.devices ?? [])) + } else { + devices.push(device) + } + } + + return devices + } + + private async resolveDeviceReference( + deviceReference: DeviceReference, + flatGroup?: boolean + ): Promise { + try { + return await apiClient.getDevice(deviceReference.url, { + flat_group: flatGroup, + }) + } catch (error) { + console.error(error) + } + return undefined + } +} + +export const deviceGroupRepository = new DeviceGroupRepository() diff --git a/services/device/src/database/repositories/device/deviceOverview.ts b/services/device/src/database/repositories/device/deviceOverview.ts new file mode 100644 index 00000000..90ec597b --- /dev/null +++ b/services/device/src/database/repositories/device/deviceOverview.ts @@ -0,0 +1,29 @@ +import { DeviceOverview } from '../../../generated/types' +import { deviceUrlFromId } from '../../../methods/utils' +import { DeviceOverviewModel } from '../../model' +import { AbstractRepository } from '@crosslab/service-common' + +export abstract class DeviceOverviewRepository extends AbstractRepository< + DeviceOverviewModel, + DeviceOverview<'request'>, + DeviceOverview<'response'> +> { + static async write( + model: DeviceOverviewModel, + data: DeviceOverview<'request'> + ): Promise { + if (data.name) model.name = data.name + if (data.description) model.description = data.description + if (data.type) model.type = data.type + } + + static async format(model: DeviceOverviewModel): Promise> { + return { + url: deviceUrlFromId(model.uuid), + type: model.type, + name: model.name, + description: model.description, + owner: model.owner, + } + } +} diff --git a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts new file mode 100644 index 00000000..00215433 --- /dev/null +++ b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts @@ -0,0 +1,45 @@ +import { InstantiableBrowserDevice } from '../../../generated/types' +import { InstantiableBrowserDeviceModel } from '../../model' +import { DeviceOverviewRepository } from './deviceOverview' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' + +export class InstantiableBrowserDeviceRepository extends AbstractRepository< + InstantiableBrowserDeviceModel, + InstantiableBrowserDevice<'request'>, + InstantiableBrowserDevice<'response'> +> { + constructor() { + super('Instantiable Browser Device') + } + + initialize(AppDataSource: AbstractApplicationDataSource): void { + this.repository = AppDataSource.getRepository(InstantiableBrowserDeviceModel) + } + + async write( + model: InstantiableBrowserDeviceModel, + data: InstantiableBrowserDevice<'request'> + ) { + await DeviceOverviewRepository.write(model, data) + + model.codeUrl = data.codeUrl + model.services = data.services + } + + async format( + model: InstantiableBrowserDeviceModel + ): Promise> { + return { + ...(await DeviceOverviewRepository.format(model)), + type: 'edge instantiable', + codeUrl: model.codeUrl, + services: model.services, + } + } +} + +export const instantiableBrowserDeviceRepository = + new InstantiableBrowserDeviceRepository() diff --git a/services/device/src/database/repositories/device/instantiableCloudDevice.ts b/services/device/src/database/repositories/device/instantiableCloudDevice.ts new file mode 100644 index 00000000..bda1e772 --- /dev/null +++ b/services/device/src/database/repositories/device/instantiableCloudDevice.ts @@ -0,0 +1,44 @@ +import { InstantiableCloudDevice } from '../../../generated/types' +import { InstantiableCloudDeviceModel } from '../../model' +import { DeviceOverviewRepository } from './deviceOverview' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' + +export class InstantiableCloudDeviceRepository extends AbstractRepository< + InstantiableCloudDeviceModel, + InstantiableCloudDevice<'request'>, + InstantiableCloudDevice<'response'> +> { + constructor() { + super('Instantiable Cloud Device') + } + + initialize(AppDataSource: AbstractApplicationDataSource): void { + this.repository = AppDataSource.getRepository(InstantiableCloudDeviceModel) + } + + async write( + model: InstantiableCloudDeviceModel, + data: InstantiableCloudDevice<'request'> + ) { + await DeviceOverviewRepository.write(model, data) + + model.instantiateUrl = data.instantiateUrl + model.services = data.services + } + + async format( + model: InstantiableCloudDeviceModel + ): Promise> { + return { + ...(await DeviceOverviewRepository.format(model)), + type: 'cloud instantiable', + instantiateUrl: model.instantiateUrl, + services: model.services, + } + } +} + +export const instantiableCloudDeviceRepository = new InstantiableCloudDeviceRepository() diff --git a/services/device/src/database/repositories/peerconnection.ts b/services/device/src/database/repositories/peerconnection.ts new file mode 100644 index 00000000..aeb695ac --- /dev/null +++ b/services/device/src/database/repositories/peerconnection.ts @@ -0,0 +1,77 @@ +import { Peerconnection } from '../../generated/types' +import { peerconnectionUrlFromId } from '../../methods/utils' +import { PeerconnectionModel } from '../model' +import { + AbstractApplicationDataSource, + AbstractRepository, + InvalidValueError, +} from '@crosslab/service-common' + +export class PeerconnectionRepository extends AbstractRepository< + PeerconnectionModel, + Peerconnection<'request'>, + Peerconnection<'response'> +> { + constructor() { + super('Peerconnection') + } + + initialize(AppDataSource: AbstractApplicationDataSource): void { + this.repository = AppDataSource.getRepository(PeerconnectionModel) + } + + async create(data?: Peerconnection<'request'>): Promise { + const model = await super.create(data) + model.status = 'waiting-for-devices' + + return model + } + + async write( + model: PeerconnectionModel, + data: Peerconnection<'request'> + ): Promise { + if (data.type) model.type = data.type + if (data.status) model.status = data.status + + if (data.devices && data.devices.length !== 2) { + throw new InvalidValueError( + `Peerconnections need exactly 2 devices, received ${data.devices?.length}` + ) + } + + if (data.devices) { + const deviceA = data.devices[0] + const deviceB = data.devices[1] + + if (!deviceA.url || !deviceB.url) { + throw new InvalidValueError( + 'One of the provided devices does not have a url' + ) + } + + model.deviceA = deviceA + model.deviceB = deviceB + } + } + + async format(model: PeerconnectionModel): Promise> { + return { + url: peerconnectionUrlFromId(model.uuid), + type: model.type, + status: model.status, + devices: [{ ...model.deviceA }, { ...model.deviceB }], + } + } + + formatOverview(model: PeerconnectionModel): Peerconnection<'response'> { + return { + url: peerconnectionUrlFromId(model.uuid), + type: model.type, + status: model.status, + devices: [{ url: model.deviceA.url }, { url: model.deviceB.url }], + } + } +} + +export const peerconnectionRepository = new PeerconnectionRepository() diff --git a/services/device/src/globals.ts b/services/device/src/globals.ts index 1e539859..2dd6514c 100644 --- a/services/device/src/globals.ts +++ b/services/device/src/globals.ts @@ -1,13 +1,5 @@ -import { APIClient } from '@cross-lab-project/api-client' import { config } from './config' - -export type PendingPeerconnectionModel = { - peerconnectionId: string - deviceA: string - deviceB: string - timeout: NodeJS.Timeout -} +import { APIClient } from '@cross-lab-project/api-client' export const apiClient = new APIClient(config.BASE_URL) -export const YEAR = 365 * 24 * 60 * 60 * 1000 export const timeoutMap: Map = new Map() diff --git a/services/device/src/index.ts b/services/device/src/index.ts index abe34ddb..247ed879 100644 --- a/services/device/src/index.ts +++ b/services/device/src/index.ts @@ -1,14 +1,13 @@ #!/usr/bin/env node - +import { config, dataSourceConfig } from './config' +import { AppDataSource } from './database/dataSource' +import { app } from './generated/index' +import { callbackHandling } from './methods/callbacks' +import { deviceHandling } from './operations/websocket' import { JWTVerify } from '@crosslab/service-common' import { IncomingMessage } from 'http' import { Socket } from 'net' import WebSocket from 'ws' -import { config } from './config' -import { AppDataSource } from './data_source' -import { app } from './generated/index' -import { callbackHandling } from './methods/callbacks' -import { deviceHandling } from './operations/websocket' declare global { namespace Express { @@ -20,7 +19,7 @@ declare global { } } -AppDataSource.initialize() +AppDataSource.initialize(dataSourceConfig) .then(() => { app.use((req, _res, next) => { for (const param in req.query) { @@ -43,11 +42,9 @@ AppDataSource.initialize() app.initService({ security: { - JWT: JWTVerify(config) as any + JWT: JWTVerify(config) as any, }, - additionalHandlers: [ - callbackHandling - ] + additionalHandlers: [callbackHandling], }) const wsServer = new WebSocket.Server({ noServer: true }) app.wsListeners = new Map() @@ -65,6 +62,7 @@ AppDataSource.initialize() } } ) + console.log('Device Service started successfully') }) .catch((err) => { console.error('Error during Data Source initialization:', err) diff --git a/services/device/src/methods/availability.ts b/services/device/src/methods/availability.ts index 14f3ae1d..8f693b3c 100644 --- a/services/device/src/methods/availability.ts +++ b/services/device/src/methods/availability.ts @@ -1,12 +1,24 @@ -import { AppDataSource } from '../data_source' -import { TimeSlotModel, AvailabilityRuleModel } from '../model' +import { AvailabilityRule, TimeSlot } from '../generated/types' + +type TimeSlotModel = { + start: number + end: number +} + +type RemoveIndex = { + [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K] +} +type AvailabilityRuleModel = Omit, 'start' | 'end'> & { + start?: number + end?: number +} /** * This function sorts a list of timeslots in ascending order of their start times. * @param availability The list of timeslots to be sorted. * @returns The sorted list of timeslots. */ -export function sortTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { +function sortTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { console.log('availability before sort:', JSON.stringify(availability, null, 4)) availability.sort((a, b) => { if (a.start < b.start) return -1 @@ -22,9 +34,7 @@ export function sortTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { * @param availability The list of timeslots in which to merge overlapping timeslots. * @returns The list of timeslots with no overlap. */ -export function mergeOverlappingTimeSlots( - availability: TimeSlotModel[] -): TimeSlotModel[] { +function mergeOverlappingTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { console.log('availability before merge:', JSON.stringify(availability, null, 4)) for (let i = 0; i < availability.length; i++) { if (i < availability.length - 1) { @@ -45,7 +55,7 @@ export function mergeOverlappingTimeSlots( * @param end The end time of the inverted list of timeslots. * @returns The inverted list of timeslots. */ -export function invertTimeSlots( +function invertTimeSlots( availability: TimeSlotModel[], start: number, end: number @@ -53,8 +63,6 @@ export function invertTimeSlots( if (availability.length === 0) return [] console.log('availability before invert:', JSON.stringify(availability, null, 4)) - const timeSlotRepository = AppDataSource.getRepository(TimeSlotModel) - // sort by starttime availability = sortTimeSlots(availability) @@ -64,26 +72,29 @@ export function invertTimeSlots( const newAvailability: TimeSlotModel[] = [] // create first timeslot - const firstTimeSlot = timeSlotRepository.create() - firstTimeSlot.start = start - firstTimeSlot.end = availability[0].start + const firstTimeSlot: TimeSlotModel = { + start, + end: availability[0].start, + } if (firstTimeSlot.start !== firstTimeSlot.end) newAvailability.push(firstTimeSlot) // create intermediate timeslots for (let i = 0; i < availability.length; i++) { if (i < availability.length - 1) { - const timeSlot = timeSlotRepository.create() - timeSlot.start = availability[i].end - timeSlot.end = availability[i + 1].start + const timeSlot: TimeSlotModel = { + start: availability[i].end, + end: availability[i + 1].start, + } newAvailability.push(timeSlot) } } // create last timeslot - const lastTimeSlot = timeSlotRepository.create() - lastTimeSlot.start = availability[availability.length - 1].end - lastTimeSlot.end = end + const lastTimeSlot: TimeSlotModel = { + start: availability[-1].end, + end, + } if (lastTimeSlot.start !== lastTimeSlot.end) newAvailability.push(lastTimeSlot) @@ -100,7 +111,7 @@ export function invertTimeSlots( * @param end The end time for deriving the timeslots. * @returns The list of timeslots containing the newly added timeslots. */ -export function addTimeSlotsFromRule( +function addTimeSlotsFromRule( availability: TimeSlotModel[], availabilityRule: AvailabilityRuleModel, start: number, @@ -110,20 +121,20 @@ export function addTimeSlotsFromRule( 'availability before adding timeslots from rule:', JSON.stringify(availability, null, 4) ) - const timeSlotRepository = AppDataSource.getRepository(TimeSlotModel) - const timeSlot = timeSlotRepository.create() - ;(timeSlot.start = - availabilityRule.start && availabilityRule.start >= start - ? availabilityRule.start - : start), - (timeSlot.end = + const timeSlot: TimeSlotModel = { + start: + availabilityRule.start && availabilityRule.start >= start + ? availabilityRule.start + : start, + end: availabilityRule.end && availabilityRule.end <= end ? availabilityRule.end - : end) + : end, + } - if (availabilityRule.frequency && availabilityRule.end) { + if (availabilityRule.repeat?.frequency && availabilityRule.end) { let frequency = 0 - switch (availabilityRule.frequency) { + switch (availabilityRule.repeat.frequency) { case 'HOURLY': frequency = 60 * 60 * 1000 break @@ -144,15 +155,16 @@ export function addTimeSlotsFromRule( timeSlot.start = start timeSlot.end = end } - const until = availabilityRule.until ?? end - let count = availabilityRule.count + const until = availabilityRule.repeat.until ?? end + let count = availabilityRule.repeat.count - let currentTimeSlot = timeSlotRepository.create() - currentTimeSlot.start = - availabilityRule.start !== undefined - ? availabilityRule.start + frequency - : start - currentTimeSlot.end = availabilityRule.end + frequency + let currentTimeSlot: TimeSlotModel = { + start: + availabilityRule.start !== undefined + ? availabilityRule.start + frequency + : start, + end: availabilityRule.end + frequency, + } while (until < currentTimeSlot.end - frequency) { if (until !== undefined) { @@ -168,14 +180,9 @@ export function addTimeSlotsFromRule( if (currentTimeSlot.start < start) currentTimeSlot.start = start if (currentTimeSlot.end > end) currentTimeSlot.end = end availability.push(currentTimeSlot) - const newCurrentTimeSlot = timeSlotRepository.create() - - if (availabilityRule.start) { - newCurrentTimeSlot.start = currentTimeSlot.start + frequency - newCurrentTimeSlot.end = currentTimeSlot.end + frequency - } else { - newCurrentTimeSlot.start = start - newCurrentTimeSlot.end = currentTimeSlot.end + frequency + const newCurrentTimeSlot: TimeSlotModel = { + start: availabilityRule.start ? currentTimeSlot.start + frequency : start, + end: currentTimeSlot.end + frequency, } currentTimeSlot = newCurrentTimeSlot @@ -198,7 +205,7 @@ export function addTimeSlotsFromRule( * @param end The end time for the availability rule. * @returns The list of timeslots containing the changes of the applied availability rule. */ -export function applyAvailabilityRule( +function applyAvailabilityRule( availability: TimeSlotModel[], availabilityRule: AvailabilityRuleModel, start: number, @@ -245,13 +252,33 @@ export function applyAvailabilityRule( * @returns The list of timeslots containing the changes of the applied availability rules. */ export function applyAvailabilityRules( - availability: TimeSlotModel[], - availabilityRules: AvailabilityRuleModel[], + availability: Required[], + availabilityRules: AvailabilityRule[], start: number, end: number -) { +): Required[] { + let newAvailability = availability.map((timeSlot) => { + return { + start: Date.parse(timeSlot.start), + end: Date.parse(timeSlot.end), + } + }) for (const availabilityRule of availabilityRules) { - availability = applyAvailabilityRule(availability, availabilityRule, start, end) + newAvailability = applyAvailabilityRule( + newAvailability, + { + ...availabilityRule, + start: Date.parse(availabilityRule.start ?? ''), + end: Date.parse(availabilityRule.end ?? ''), + }, + start, + end + ) } - return availability + return newAvailability.map((timeSlotModel) => { + return { + start: new Date(timeSlotModel.start).toISOString(), + end: new Date(timeSlotModel.end).toISOString(), + } + }) } diff --git a/services/device/src/methods/callbacks.ts b/services/device/src/methods/callbacks.ts index 2b979007..17ac2f94 100644 --- a/services/device/src/methods/callbacks.ts +++ b/services/device/src/methods/callbacks.ts @@ -1,7 +1,8 @@ -import express from 'express' -import fetch from 'node-fetch' import { config } from '../config' -import { AppDataSource } from '../data_source' +import { AppDataSource } from '../database/dataSource' +import { PeerconnectionModel } from '../database/model' +import { deviceRepository } from '../database/repositories/device' +import { peerconnectionRepository } from '../database/repositories/peerconnection' import { isConcreteDevice, isDeviceGroup, @@ -9,16 +10,14 @@ import { isInstantiableCloudDevice, } from '../generated/types' import { apiClient, timeoutMap } from '../globals' -import { PeerconnectionModel } from '../model' -import { InvalidValueError, MalformedBodyError } from '../types/errors' -import { DeviceModel } from '../types/helper' -import { formatDevice, formatPeerconnection } from './database/format' -import { startSignaling } from './signaling' +import { DeviceModel } from '../types/device' +import { signalingQueue } from './signaling' +import { InvalidValueError, MalformedBodyError } from '@crosslab/service-common' +import express from 'express' +import fetch from 'node-fetch' export const callbackUrl: string = - config.BASE_URL + - (config.BASE_URL.endsWith('/') ? '' : '/') + - 'callbacks/device' + config.BASE_URL + (config.BASE_URL.endsWith('/') ? '' : '/') + 'callbacks/device' export const changedCallbacks = new Map>() export const closedCallbacks = new Map>() export const statusChangedCallbacks = new Map>() @@ -133,31 +132,37 @@ async function handleDeviceChangedEventCallback(callback: any): Promise<200 | 41 400 // NOTE: error code ) } - const pendingConnectionsA = await AppDataSource.getRepository(PeerconnectionModel).find({ + const pendingConnectionsA = await AppDataSource.getRepository( + PeerconnectionModel + ).find({ where: { + status: 'waiting-for-devices', deviceA: { - url: device.url - } + url: device.url, + }, }, relations: { deviceA: true, - deviceB: true - } + deviceB: true, + }, }) - const pendingConnectionsB = await AppDataSource.getRepository(PeerconnectionModel).find({ + const pendingConnectionsB = await AppDataSource.getRepository( + PeerconnectionModel + ).find({ where: { + status: 'waiting-for-devices', deviceB: { - url: device.url - } + url: device.url, + }, }, relations: { deviceA: true, - deviceB: true - } + deviceB: true, + }, }) const pendingConnections = [...pendingConnectionsA, ...pendingConnectionsB] if (pendingConnections.length === 0) { - return 410 + return 410 // TODO: check if 410 is the right choice here } for (const pendingConnection of pendingConnections) { const deviceA = await apiClient.getDevice(pendingConnection.deviceA.url) @@ -165,7 +170,7 @@ async function handleDeviceChangedEventCallback(callback: any): Promise<200 | 41 if (deviceA.connected && deviceB.connected) { clearTimeout(timeoutMap.get(pendingConnection.uuid)) - await startSignaling(pendingConnection) + signalingQueue.addPeerconnection(pendingConnection) timeoutMap.delete(pendingConnection.uuid) } } @@ -186,11 +191,9 @@ export async function sendChangedCallback(device: DeviceModel) { body: JSON.stringify({ callbackType: 'event', eventType: 'device-changed', - device: await formatDevice(device), + device: await deviceRepository.format(device), }), - headers: [ - ["Content-Type", "application/json"] - ] + headers: [['Content-Type', 'application/json']], }) if (res.status === 410) { @@ -215,11 +218,9 @@ export async function sendClosedCallback(peerconnection: PeerconnectionModel) { body: JSON.stringify({ callbackType: 'event', eventType: 'peerconnnection-closed', - peerconnection: formatPeerconnection(peerconnection), + peerconnection: await peerconnectionRepository.format(peerconnection), }), - headers: [ - ["Content-Type", "application/json"] - ] + headers: [['Content-Type', 'application/json']], }) if (res.status === 410) { @@ -240,17 +241,17 @@ export async function sendStatusChangedCallback(peerconnection: PeerconnectionMo console.log(`Sending statusChangedCallback for peerconnection ${peerconnection.uuid}`) const urls = statusChangedCallbacks.get(peerconnection.uuid) ?? [] for (const url of urls) { - console.log(`Sending statusChangedCallback for peerconnection ${peerconnection.uuid} to url ${url}`) + console.log( + `Sending statusChangedCallback for peerconnection ${peerconnection.uuid} to url ${url}` + ) const res = await fetch(url, { method: 'post', body: JSON.stringify({ callbackType: 'event', eventType: 'peerconnection-status-changed', - peerconnection: formatPeerconnection(peerconnection), + peerconnection: await peerconnectionRepository.format(peerconnection), }), - headers: [ - ["Content-Type", "application/json"] - ] + headers: [['Content-Type', 'application/json']], }) if (res.status === 410) { diff --git a/services/device/src/methods/database/create.ts b/services/device/src/methods/database/create.ts deleted file mode 100644 index 1bd46f4c..00000000 --- a/services/device/src/methods/database/create.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { AppDataSource } from '../../data_source' -import { - isConcreteDevice, - isDeviceGroup, - isInstantiableBrowserDevice, - isInstantiableCloudDevice, -} from '../../generated/types' -import { - ConcreteDeviceModel, - DeviceGroupModel, - InstantiableBrowserDeviceModel, - InstantiableCloudDeviceModel, -} from '../../model' -import { InvalidValueError } from '../../types/errors' -import { - DeviceTypeName, - DeviceModelFromName, - WriteDeviceFromModel, - DeviceModel, -} from '../../types/helper' -import { - writeConcreteDevice, - writeDeviceGroup, - writeInstantiableBrowserDevice, - writeInstantiableCloudDevice, -} from './write' - -/** - * This function attempts to create a device model with a given type. - * @param type The type of device model to create. - * @throws {InvalidValueError} Thrown if the given type does not match any known device type. - * @returns The created device model. - */ -export function createDeviceModel( - type: T -): DeviceModelFromName { - switch (type) { - case 'device': - return AppDataSource.getRepository( - ConcreteDeviceModel - ).create() as DeviceModelFromName - case 'group': - return AppDataSource.getRepository( - DeviceGroupModel - ).create() as DeviceModelFromName - case 'edge instantiable': - return AppDataSource.getRepository( - InstantiableBrowserDeviceModel - ).create() as DeviceModelFromName - case 'cloud instantiable': - return AppDataSource.getRepository( - InstantiableCloudDeviceModel - ).create() as DeviceModelFromName - default: - throw new InvalidValueError( - 'The given type does not match any known device type', - 500 - ) - } -} - -/** - * This function attempts to create a device model with the data provided. - * @param data The provided data in the form of a device. - * @throws {InvalidValueError} Thrown if the type of the device does not match any known device type - * @returns The created device model. - */ -export function createDeviceModelFromDevice( - data: WriteDeviceFromModel -): T { - if (isConcreteDevice(data)) { - const deviceModel = createDeviceModel('device') - writeConcreteDevice(deviceModel, data) - return deviceModel as T - } else if (isDeviceGroup(data)) { - const deviceModel = createDeviceModel('group') - writeDeviceGroup(deviceModel, data) - return deviceModel as T - } else if (isInstantiableBrowserDevice(data)) { - const deviceModel = createDeviceModel('edge instantiable') - writeInstantiableBrowserDevice(deviceModel, data) - return deviceModel as T - } else if (isInstantiableCloudDevice(data)) { - const deviceModel = createDeviceModel('cloud instantiable') - writeInstantiableCloudDevice(deviceModel, data) - return deviceModel as T - } else { - throw new InvalidValueError( - 'The device does not match any known device type', - 500 - ) - } -} diff --git a/services/device/src/methods/database/delete.ts b/services/device/src/methods/database/delete.ts deleted file mode 100644 index 9d3ac5c1..00000000 --- a/services/device/src/methods/database/delete.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { AppDataSource } from '../../data_source' -import { - DeviceOverviewModel, - isConcreteDeviceModel, - ConcreteDeviceModel, - isDeviceGroupModel, - DeviceGroupModel, - isInstantiableBrowserDeviceModel, - InstantiableBrowserDeviceModel, - isInstantiableCloudDeviceModel, - InstantiableCloudDeviceModel, -} from '../../model' -import { InvalidValueError } from '../../types/errors' - -/** - * This function attempts to delete a given device model. - * @param deviceModel The device model to be deleted. - * @throws {InvalidValueError} Thrown when the given device model does not match any known device type. - */ -export async function deleteDeviceModel(deviceModel: DeviceOverviewModel) { - if (isConcreteDeviceModel(deviceModel)) { - const concreteDeviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) - await concreteDeviceRepository.softDelete(deviceModel.uuid) - } else if (isDeviceGroupModel(deviceModel)) { - const deviceGroupRepository = AppDataSource.getRepository(DeviceGroupModel) - await deviceGroupRepository.softDelete(deviceModel.uuid) - } else if (isInstantiableBrowserDeviceModel(deviceModel)) { - const instantiableBrowserDeviceRepository = AppDataSource.getRepository( - InstantiableBrowserDeviceModel - ) - await instantiableBrowserDeviceRepository.softDelete(deviceModel.uuid) - } else if (isInstantiableCloudDeviceModel(deviceModel)) { - const instantiableCloudDeviceRepository = AppDataSource.getRepository( - InstantiableCloudDeviceModel - ) - await instantiableCloudDeviceRepository.softDelete(deviceModel.uuid) - } else { - throw new InvalidValueError( - 'The device model to be deleted does not match any known device type', - 500 - ) - } -} diff --git a/services/device/src/methods/database/find.ts b/services/device/src/methods/database/find.ts deleted file mode 100644 index 98f4f1a2..00000000 --- a/services/device/src/methods/database/find.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { AppDataSource } from '../../data_source' -import { - ConcreteDeviceModel, - DeviceGroupModel, - InstantiableBrowserDeviceModel, - InstantiableCloudDeviceModel, -} from '../../model' -import { InconsistentDatabaseError } from '../../types/errors' -import { DeviceModel } from '../../types/helper' - -/** - * This function retrieves a device from the database by its UUID. - * @param uuid The UUID of the device to be retrieved. - * @throws {InconsistentDatabaseError} Thrown if device is found as multiple types. - * @returns The retrieved device. - */ -export async function findDeviceModelByUUID( - uuid: string -): Promise { - const concreteDeviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) - const deviceGroupRepository = AppDataSource.getRepository(DeviceGroupModel) - const instantiableBrowserDeviceRepository = AppDataSource.getRepository( - InstantiableBrowserDeviceModel - ) - const instantiableCloudDeviceRepository = AppDataSource.getRepository( - InstantiableCloudDeviceModel - ) - const concreteDevice = await concreteDeviceRepository.findOne({ - where: { - uuid: uuid, - }, - relations: { - announcedAvailability: true, - }, - }) - const deviceGroup = await deviceGroupRepository.findOne({ - where: { - uuid: uuid, - }, - relations: { - devices: true, - }, - }) - const instantiableBrowserDevice = await instantiableBrowserDeviceRepository.findOne({ - where: { - uuid: uuid, - }, - relations: { - instances: true, - }, - }) - const instantiableCloudDevice = await instantiableCloudDeviceRepository.findOne({ - where: { - uuid: uuid, - }, - relations: { - instances: true, - }, - }) - - if ( - (concreteDevice && deviceGroup) || - (concreteDevice && instantiableBrowserDevice) || - (concreteDevice && instantiableCloudDevice) || - (deviceGroup && instantiableBrowserDevice) || - (deviceGroup && instantiableCloudDevice) || - (instantiableBrowserDevice && instantiableCloudDevice) - ) - throw new InconsistentDatabaseError('Multiple devices found for same uuid') - - if (concreteDevice) return concreteDevice - if (deviceGroup) return deviceGroup - if (instantiableBrowserDevice) return instantiableBrowserDevice - if (instantiableCloudDevice) return instantiableCloudDevice - return undefined -} diff --git a/services/device/src/methods/database/format.ts b/services/device/src/methods/database/format.ts deleted file mode 100644 index 2cf435e5..00000000 --- a/services/device/src/methods/database/format.ts +++ /dev/null @@ -1,264 +0,0 @@ -import { - ServiceConfig, - DeviceReference, - ConfiguredDeviceReference, - PeerconnectionOverview, - Peerconnection, - ConcreteDevice, - DeviceOverview, - TimeSlot, - DeviceGroup, - InstantiableBrowserDevice, - InstantiableCloudDevice, -} from '../../generated/types' -import { - ServiceConfigModel, - DeviceReferenceModel, - PeerconnectionModel, - ConcreteDeviceModel, - DeviceOverviewModel, - TimeSlotModel, - DeviceGroupModel, - InstantiableBrowserDeviceModel, - InstantiableCloudDeviceModel, - isConcreteDeviceModel, - isDeviceGroupModel, - isInstantiableBrowserDeviceModel, - isInstantiableCloudDeviceModel, -} from '../../model' -import { InvalidValueError } from '../../types/errors' -import { DeviceModel, DeviceFromModel, Device } from '../../types/helper' -import { - deviceUrlFromId, - flattenDeviceGroup, - peerconnectionUrlFromId, - resolveDeviceReference, -} from '../utils' - -// Devices - -/** - * This function attempts to format a given device model to its corresponding device type. - * @param deviceModel The device model to be formatted. - * @throws {InvalidValueError} Thrown if the given device model does not match any known device type. - * @returns The formatted device model. - */ -export async function formatDevice( - deviceModel: T -): Promise> { - if (isConcreteDeviceModel(deviceModel)) { - return formatConcreteDevice(deviceModel) as DeviceFromModel - } else if (isDeviceGroupModel(deviceModel)) { - return (await formatDeviceGroup(deviceModel)) as DeviceFromModel - } else if (isInstantiableBrowserDeviceModel(deviceModel)) { - return formatInstantiableBrowserDevice(deviceModel) as DeviceFromModel - } else if (isInstantiableCloudDeviceModel(deviceModel)) { - return formatInstantiableCloudDevice(deviceModel) as DeviceFromModel - } else { - throw new InvalidValueError( - 'The device model to be formatted does not match any known device type', - 500 - ) - } -} - -/** - * This function formats a {@link TimeSlotModel} to a {@link TimeSlot}. - * @param timeSlot The {@link TimeSlotModel} to be formatted. - * @returns The resulting {@link TimeSlot}. - */ -export function formatTimeSlot(timeSlot: TimeSlotModel): TimeSlot { - return { - start: new Date(timeSlot.start).toISOString(), - end: new Date(timeSlot.end).toISOString(), - } -} - -/** - * This function formats a {@link DeviceOverviewModel} to a {@link DeviceOverview}. - * @param device The {@link DeviceOverviewModel} to be formatted. - * @returns The resulting {@link DeviceOverview}. - */ -export function formatDeviceOverview(device: DeviceOverviewModel): DeviceOverview { - return { - url: deviceUrlFromId(device.uuid), - name: device.name, - description: device.description, - type: device.type, - owner: device.owner, - } -} - -/** - * This function formats a {@link ConcreteDeviceModel} to a {@link ConcreteDevice}. - * @param device The {@link ConcreteDeviceModel} to be formatted. - * @returns The resulting {@link ConcreteDevice}. - */ -function formatConcreteDevice(device: ConcreteDeviceModel): ConcreteDevice { - return { - url: deviceUrlFromId(device.uuid), - name: device.name, - description: device.description, - type: device.type, - owner: device.owner, - announcedAvailability: device.announcedAvailability - ? device.announcedAvailability.map(formatTimeSlot) - : undefined, - connected: device.connected !== undefined ? device.connected : undefined, - experiment: device.experiment ? device.experiment : undefined, - services: device.services - ? device.services.map((sd) => JSON.parse(sd.description)) - : undefined, - } -} - -/** - * This function formats a {@link DeviceGroupModel} to a {@link DeviceGroup}. - * @param deviceGroup The {@link DeviceGroupModel} to be formatted. - * @param flat_group If true then the formatted {@link DeviceGroup} will contain no further device groups. - * @returns The resulting {@link DeviceGroup}. - */ -async function formatDeviceGroup( - deviceGroup: DeviceGroupModel, - flat_group: boolean = false -): Promise { - const devices: Device[] = [] - if (deviceGroup.devices) { - for (const d of deviceGroup.devices) { - const resolvedDevice = await resolveDeviceReference(d, flat_group) - if (resolvedDevice) { - if (resolvedDevice.type != 'group') devices.push(resolvedDevice) - if (resolvedDevice.type == 'group' && !flat_group) - devices.push(resolvedDevice) - if (resolvedDevice.type == 'group' && flat_group) - devices.push(...flattenDeviceGroup(resolvedDevice)) - } - } - } - - return { - url: deviceUrlFromId(deviceGroup.uuid), - name: deviceGroup.name, - description: deviceGroup.description, - type: deviceGroup.type, - owner: deviceGroup.owner, - devices: devices.filter((v, i, s) => s.findIndex((d) => d.url == v.url) == i), - } -} - -/** - * This function formats a {@link InstantiableBrowserDeviceModel} to a {@link InstantiableBrowserDevice}. - * @param instantiableBrowserDevice The {@link InstantiableBrowserDeviceModel} to be formatted. - * @returns The resulting {@link InstantiableBrowserDevice}. - */ -function formatInstantiableBrowserDevice( - instantiableBrowserDevice: InstantiableBrowserDeviceModel -): InstantiableBrowserDevice { - return { - url: deviceUrlFromId(instantiableBrowserDevice.uuid), - name: instantiableBrowserDevice.name, - description: instantiableBrowserDevice.description, - type: instantiableBrowserDevice.type, - owner: instantiableBrowserDevice.owner, - code_url: instantiableBrowserDevice.codeUrl, - } -} - -/** - * This function formats a {@link InstantiableCloudDeviceModel} to a {@link instantiableCloudDevice}. - * @param instantiableCloudDevice The {@link InstantiableCloudDeviceModel} to be formatted. - * @returns The resulting {@link instantiableCloudDevice}. - */ -function formatInstantiableCloudDevice( - instantiableCloudDevice: InstantiableCloudDeviceModel -): InstantiableCloudDevice { - return { - url: deviceUrlFromId(instantiableCloudDevice.uuid), - name: instantiableCloudDevice.name, - description: instantiableCloudDevice.description, - type: instantiableCloudDevice.type, - owner: instantiableCloudDevice.owner, - instantiate_url: instantiableCloudDevice.instantiateUrl, - } -} - -// Peerconnections - -/** - * This function formats a {@link ServiceConfigModel} to a {@link ServiceConfig}. - * @param serviceConfig The {@link ServiceConfigModel} to be formatted. - * @returns The resulting {@link ServiceConfig}. - */ -export function formatServiceConfig(serviceConfig: ServiceConfigModel): ServiceConfig { - return { - ...JSON.parse(serviceConfig.config ?? '{}'), - serviceType: serviceConfig.serviceType, - serviceId: serviceConfig.serviceId, - remoteServiceId: serviceConfig.remoteServiceId, - } -} - -/** - * This function formats a {@link DeviceReferenceModel} to a {@link DeviceReference}. - * @param device The {@link DeviceReferenceModel} to be formatted. - * @returns The resulting {@link DeviceReference}. - */ -export function formatDeviceReference(device: DeviceReferenceModel): DeviceReference { - return { - url: device.url, - } -} - -/** - * This function formats a {@link DeviceReferenceModel} to a {@link ConfiguredDeviceReference}. - * @param device The {@link DeviceReferenceModel} to be formatted. - * @returns The resulting {@link ConfiguredDeviceReference}. - */ -export function formatConfiguredDeviceReference( - device: DeviceReferenceModel -): ConfiguredDeviceReference { - return { - url: device.url, - config: device.config - ? { - services: device.config.map(formatServiceConfig), - } - : undefined, - } -} - -/** - * This function formats a {@link PeerconnectionModel} to a {@link PeerconnectionOverview}. - * @param peerconnection The {@link PeerconnectionModel} to be formatted. - * @returns The resulting {@link PeerconnectionOverview}. - */ -export function formatPeerconnectionOverview( - peerconnection: PeerconnectionModel -): PeerconnectionOverview { - return { - devices: [ - formatDeviceReference(peerconnection.deviceA), - formatDeviceReference(peerconnection.deviceB), - ], - url: peerconnectionUrlFromId(peerconnection.uuid), - status: peerconnection.status, - } -} - -/** - * This function formats a {@link PeerconnectionModel} to a {@link Peerconnection}. - * @param peerconnection The {@link PeerconnectionModel} to be formatted. - * @returns The resulting {@link Peerconnection}. - */ -export function formatPeerconnection( - peerconnection: PeerconnectionModel -): Peerconnection { - return { - devices: [ - formatConfiguredDeviceReference(peerconnection.deviceA), - formatConfiguredDeviceReference(peerconnection.deviceB), - ], - url: peerconnectionUrlFromId(peerconnection.uuid), - status: peerconnection.status, - } -} diff --git a/services/device/src/methods/database/save.ts b/services/device/src/methods/database/save.ts deleted file mode 100644 index f59c571c..00000000 --- a/services/device/src/methods/database/save.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { AppDataSource } from '../../data_source' -import { - DeviceOverviewModel, - isConcreteDeviceModel, - ConcreteDeviceModel, - isDeviceGroupModel, - DeviceGroupModel, - isInstantiableBrowserDeviceModel, - InstantiableBrowserDeviceModel, - isInstantiableCloudDeviceModel, - InstantiableCloudDeviceModel, -} from '../../model' -import { InvalidValueError } from '../../types/errors' - -/** - * This function attempts to save a device model in its correct repository. - * @param deviceModel The device model to be saved. - */ -export async function saveDeviceModel(deviceModel: DeviceOverviewModel) { - if (isConcreteDeviceModel(deviceModel)) { - await AppDataSource.getRepository(ConcreteDeviceModel).save(deviceModel) - } else if (isDeviceGroupModel(deviceModel)) { - await AppDataSource.getRepository(DeviceGroupModel).save(deviceModel) - } else if (isInstantiableBrowserDeviceModel(deviceModel)) { - await AppDataSource.getRepository(InstantiableBrowserDeviceModel).save( - deviceModel - ) - } else if (isInstantiableCloudDeviceModel(deviceModel)) { - await AppDataSource.getRepository(InstantiableCloudDeviceModel).save(deviceModel) - } else { - throw new InvalidValueError( - 'The device model to be saved does not match any known device type', - 500 - ) - } -} diff --git a/services/device/src/methods/database/write.ts b/services/device/src/methods/database/write.ts deleted file mode 100644 index fb8f8cd6..00000000 --- a/services/device/src/methods/database/write.ts +++ /dev/null @@ -1,275 +0,0 @@ -import { AppDataSource } from '../../data_source' -import { - ServiceConfig, - ConfiguredDeviceReference, - Peerconnection, - AvailabilityRule, - DeviceOverview, - ConcreteDevice, - DeviceGroup, - InstantiableBrowserDevice, - InstantiableCloudDevice, - isConcreteDevice, - isDeviceGroup, - isInstantiableBrowserDevice, - isInstantiableCloudDevice, -} from '../../generated/types' -import { YEAR } from '../../globals' -import { - ServiceConfigModel, - DeviceReferenceModel, - PeerconnectionModel, - DeviceOverviewModel, - AvailabilityRuleModel, - ConcreteDeviceModel, - DeviceGroupModel, - InstantiableBrowserDeviceModel, - InstantiableCloudDeviceModel, - ServiceModel, - isConcreteDeviceModel, - isDeviceGroupModel, - isInstantiableBrowserDeviceModel, - isInstantiableCloudDeviceModel, -} from '../../model' -import { InvalidValueError } from '../../types/errors' -import { DeviceModel, WriteDeviceFromModel } from '../../types/helper' -import { applyAvailabilityRules } from '../availability' - -// Devices - -/** - * This function attempts to write the data of a device to a device model. - * @param deviceModel The device model the data should be written to. - * @param device The device providing the data to be written. - * @throws {InvalidValueError} Thrown when the given device model and device do not - * match any known device type or they have a different type from one another. - */ -export function writeDevice( - deviceModel: T, - device: WriteDeviceFromModel -) { - if (isConcreteDeviceModel(deviceModel) && isConcreteDevice(device)) { - writeConcreteDevice(deviceModel, device) - } else if (isDeviceGroupModel(deviceModel) && isDeviceGroup(device)) { - writeDeviceGroup(deviceModel, device) - } else if ( - isInstantiableBrowserDeviceModel(deviceModel) && - isInstantiableBrowserDevice(device, "request") - ) { - writeInstantiableBrowserDevice(deviceModel, device) - } else if ( - isInstantiableCloudDeviceModel(deviceModel) && - isInstantiableCloudDevice(device) - ) { - writeInstantiableCloudDevice(deviceModel, device) - } else { - throw new InvalidValueError( - 'The device model and device to be written do not match any known device type or they have a different type from one another', - 500 - ) - } -} - -/** - * This function writes the data of an {@link AvailabilityRule} to an {@link AvailabilityRuleModel}. - * @param availabilityRuleModel The {@link AvailabilityRuleModel} the data should be written to. - * @param availabilityRule The {@link AvailabilityRule} providing the data to be written. - */ -export function writeAvailabilityRule( - availabilityRuleModel: AvailabilityRuleModel, - availabilityRule: AvailabilityRule -) { - availabilityRuleModel.available = availabilityRule.available ?? true - availabilityRuleModel.start = availabilityRule.start - ? new Date(availabilityRule.start).getTime() - : undefined - availabilityRuleModel.end = availabilityRule.end - ? new Date(availabilityRule.end).getTime() - : undefined - if (availabilityRule.repeat) { - availabilityRuleModel.frequency = availabilityRule.repeat.frequency - availabilityRuleModel.until = availabilityRule.repeat.until - ? new Date(availabilityRule.repeat.until).getTime() - : undefined - availabilityRuleModel.count = availabilityRule.repeat.count - } -} - -/** - * This function writes the data of a {@link DeviceOverview} to a {@link DeviceOverviewModel}. - * @param deviceOverviewModel The {@link DeviceOverviewModel} the data should be written to. - * @param deviceOverview The {@link DeviceOverview} providing the data to be written. - */ -export function writeDeviceOverview( - deviceOverviewModel: DeviceOverviewModel, - deviceOverview: DeviceOverview -) { - if (deviceOverview.name) deviceOverviewModel.name = deviceOverview.name - if (deviceOverview.description) deviceOverviewModel.description = deviceOverview.description - if (deviceOverview.type) deviceOverviewModel.type = deviceOverview.type -} - -/** - * This function writes the data of a {@link ConcreteDevice} to a {@link ConcreteDeviceModel}. - * @param concreteDeviceModel The {@link ConcreteDeviceModel} the data should be written to. - * @param concreteDevice The {@link ConcreteDevice} providing the data to be written. - */ -export function writeConcreteDevice( - concreteDeviceModel: ConcreteDeviceModel, - concreteDevice: ConcreteDevice & { announcedAvailability?: AvailabilityRule[] } -) { - writeDeviceOverview(concreteDeviceModel, concreteDevice) - - concreteDeviceModel.connected = false - concreteDeviceModel.token = undefined - concreteDeviceModel.experiment = concreteDevice.experiment - - if (concreteDevice.services) { - if (!concreteDeviceModel.services) concreteDeviceModel.services = [] - const serviceRepository = AppDataSource.getRepository(ServiceModel) - for (const service of concreteDevice.services) { - const serviceModel = serviceRepository.create() - serviceModel.description = JSON.stringify(service) - concreteDeviceModel.services.push(serviceModel) - } - } - - if (concreteDevice.announcedAvailability) { - if (!concreteDeviceModel.availabilityRules) - concreteDeviceModel.availabilityRules = [] - const availabilityRuleRepository = - AppDataSource.getRepository(AvailabilityRuleModel) - for (const availabilityRule of concreteDevice.announcedAvailability) { - const availabilityRuleModel = availabilityRuleRepository.create() - writeAvailabilityRule(availabilityRuleModel, availabilityRule) - concreteDeviceModel.availabilityRules.push(availabilityRuleModel) - } - } - - if (!concreteDeviceModel.announcedAvailability) - concreteDeviceModel.announcedAvailability = [] - if (concreteDeviceModel.availabilityRules) { - concreteDeviceModel.announcedAvailability = [] - const start = Date.now() - const end = start + YEAR - concreteDeviceModel.announcedAvailability = applyAvailabilityRules( - concreteDeviceModel.announcedAvailability, - concreteDeviceModel.availabilityRules, - start, - end - ) - } -} - -/** - * This function writes the data of a {@link DeviceGroup} to a {@link DeviceGroupModel}. - * @param deviceGroupModel The {@link DeviceGroupModel} the data should be written to. - * @param deviceGroup The {@link DeviceGroup} providing the data to be written. - */ -export function writeDeviceGroup( - deviceGroupModel: DeviceGroupModel, - deviceGroup: DeviceGroup -) { - writeDeviceOverview(deviceGroupModel, deviceGroup) - - if (deviceGroup.devices) { - if (!deviceGroupModel.devices) deviceGroupModel.devices = [] - const deviceReferenceRepository = - AppDataSource.getRepository(DeviceReferenceModel) - for (const deviceReference of deviceGroup.devices) { - const deviceReferenceModel = deviceReferenceRepository.create() - deviceReferenceModel.url = deviceReference.url ?? '' - deviceGroupModel.devices.push(deviceReferenceModel) - } - } -} - -/** - * This function writes the data of a {@link instantiableBrowserDevice} to a {@link InstantiableBrowserDeviceModel}. - * @param instantiableBrowserDeviceModel The {@link InstantiableBrowserDeviceModel} the data should be written to. - * @param instantiableBrowserDevice The {@link instantiableBrowserDevice} providing the data to be written. - */ -export function writeInstantiableBrowserDevice( - instantiableBrowserDeviceModel: InstantiableBrowserDeviceModel, - instantiableBrowserDevice: InstantiableBrowserDevice -) { - writeDeviceOverview(instantiableBrowserDeviceModel, instantiableBrowserDevice) - instantiableBrowserDeviceModel.codeUrl = instantiableBrowserDevice.code_url -} - -/** - * This function writes the data of a {@link InstantiableCloudDevice} to a {@link InstantiableCloudDeviceModel}. - * @param instantiableCloudDeviceModel The {@link InstantiableCloudDeviceModel} the data should be written to. - * @param instantiableCloudDevice The {@link InstantiableCloudDevice} providing the data to be written. - */ -export function writeInstantiableCloudDevice( - instantiableCloudDeviceModel: InstantiableCloudDeviceModel, - instantiableCloudDevice: InstantiableCloudDevice -) { - writeDeviceOverview(instantiableCloudDeviceModel, instantiableCloudDevice) - instantiableCloudDeviceModel.instantiateUrl = instantiableCloudDevice.instantiate_url -} - -// Peerconnections - -/** - * This function writes the data of a {@link ServiceConfig} to a {@link ServiceConfigModel}. - * @param serviceConfigModel The {@link ServiceConfigModel} the data should be written to. - * @param serviceConfig The {@link ServiceConfig} providing the data to be written. - */ -export function writeServiceConfig( - serviceConfigModel: ServiceConfigModel, - serviceConfig: ServiceConfig -) { - serviceConfigModel.serviceType = serviceConfig.serviceType - serviceConfigModel.serviceId = serviceConfig.serviceId - serviceConfigModel.remoteServiceId = serviceConfig.remoteServiceId - serviceConfigModel.config = JSON.stringify(serviceConfig) -} - -/** - * This function writes the data of a {@link ConfiguredDeviceReference} to a {@link DeviceReferenceModel}. - * @param configuredDeviceReferenceModel The {@link DeviceReferenceModel} the data should be written to. - * @param configuredDeviceReference The {@link ConfiguredDeviceReference} providing the data to be written. - */ -export async function writeConfiguredDeviceReference( - configuredDeviceReferenceModel: DeviceReferenceModel, - configuredDeviceReference: ConfiguredDeviceReference -) { - const serviceConfigRepository = AppDataSource.getRepository(ServiceConfigModel) - - if (configuredDeviceReference.url) - configuredDeviceReferenceModel.url = configuredDeviceReference.url - if (configuredDeviceReference.config && configuredDeviceReference) { - if (configuredDeviceReference.config.services) { - configuredDeviceReferenceModel.config = [] - for (const serviceConfig of configuredDeviceReference.config.services) { - const serviceConfigModel = serviceConfigRepository.create() - writeServiceConfig(serviceConfigModel, serviceConfig) - configuredDeviceReferenceModel.config.push(serviceConfigModel) - } - } - } -} - -/** - * This function writes the data of a {@link Peerconnection} to a {@link PeerconnectionModel}. - * @param peerconnectionModel The {@link PeerconnectionModel} the data should be written to. - * @param peerconnection The {@link Peerconnection} providing the data to be written. - */ -export async function writePeerconnection( - peerconnectionModel: PeerconnectionModel, - peerconnection: Peerconnection -) { - peerconnectionModel.status = 'waiting-for-devices' - if (peerconnection.devices) { - const deviceReferenceRepository = - AppDataSource.getRepository(DeviceReferenceModel) - const deviceReferenceA = deviceReferenceRepository.create() - const deviceReferenceB = deviceReferenceRepository.create() - await writeConfiguredDeviceReference(deviceReferenceA, peerconnection.devices[0]) - await writeConfiguredDeviceReference(deviceReferenceB, peerconnection.devices[1]) - peerconnectionModel.deviceA = deviceReferenceA - peerconnectionModel.deviceB = deviceReferenceB - } -} diff --git a/services/device/src/methods/messageHandling.ts b/services/device/src/methods/messageHandling.ts index d31f27ca..f0cd6cf2 100644 --- a/services/device/src/methods/messageHandling.ts +++ b/services/device/src/methods/messageHandling.ts @@ -1,8 +1,22 @@ +import { ConcreteDeviceModel } from '../database/model' import { SignalingMessage, Message, isSignalingMessage } from '../generated/types' import { apiClient } from '../globals' -import { ConcreteDeviceModel } from '../model' -import { MissingPropertyError, UnrelatedPeerconnectionError } from '../types/errors' import { deviceUrlFromId } from './utils' +import { + MissingPropertyError, + UnrelatedPeerconnectionError, +} from '@crosslab/service-common' + +/** + * This function handles a message for a device. + * @param device The device for which to handle the message. + * @param message The message to be handled. + */ +export function handleDeviceMessage(device: ConcreteDeviceModel, message: Message) { + if (isSignalingMessage(message)) { + handleSignalingMessage(device, message) + } +} /** * This function handles a signaling message for a device. @@ -47,14 +61,3 @@ async function handleSignalingMessage( ) } } - -/** - * This function handles a message for a device. - * @param device The device for which to handle the message. - * @param message The message to be handled. - */ -export function handleDeviceMessage(device: ConcreteDeviceModel, message: Message) { - if (isSignalingMessage(message)) { - handleSignalingMessage(device, message) - } -} diff --git a/services/device/src/methods/signaling.ts b/services/device/src/methods/signaling.ts index c786a378..0ce60550 100644 --- a/services/device/src/methods/signaling.ts +++ b/services/device/src/methods/signaling.ts @@ -1,18 +1,65 @@ -import { AppDataSource } from '../data_source' +import { AppDataSource } from '../database/dataSource' +import { PeerconnectionModel } from '../database/model' import { CreatePeerconnectionMessage } from '../generated/types' import { apiClient } from '../globals' -import { PeerconnectionModel } from '../model' import { sendStatusChangedCallback } from './callbacks' -import { formatServiceConfig } from './database/format' import { peerconnectionUrlFromId } from './utils' +import Queue from 'queue' + +class SignalingQueue { + private queue: Queue + + constructor() { + this.queue = new Queue({ + autostart: true, + concurrency: 1, + }) + } + + public addPeerconnection(peerconnection: PeerconnectionModel) { + this.queue.push(async function () { + try { + await startSignaling(peerconnection.uuid) + } catch (error) { + if (error instanceof Error) console.log(error.message) + else console.log(error) + } + }) + } +} + +export const signalingQueue = new SignalingQueue() /** * This function starts the signaling process for a peerconnection. * @param peerconnection The peerconnection the signaling process should be started for. * @throws Throws errors of the {@link apiClient.sendSignalingMessage | sendSignalingMessage()} function of the api-client. */ -export async function startSignaling(peerconnection: PeerconnectionModel) { - console.log(`Starting signaling for ${peerconnection.uuid}`) +async function startSignaling(peerconnectionId: string) { + console.log(`Starting signaling for ${peerconnectionId}`) + const peerconnectionRepository = AppDataSource.getRepository(PeerconnectionModel) + + const peerconnection = await peerconnectionRepository.findOneOrFail({ + where: { + uuid: peerconnectionId, + }, + relations: { + deviceA: { + config: true, + }, + deviceB: { + config: true, + }, + }, + }) + + if (peerconnection.status !== 'waiting-for-devices') { + console.log( + `status of peerconnection '${peerconnection.uuid}' is not 'waiting-for-devices', '${peerconnection.status}'` + ) + return + } + const common = { messageType: 'command', command: 'createPeerconnection', @@ -20,39 +67,37 @@ export async function startSignaling(peerconnection: PeerconnectionModel) { connectionUrl: peerconnectionUrlFromId(peerconnection.uuid), } - if (peerconnection.status !== "waiting-for-devices") { - return - } - const createPeerConnectionMessageA: CreatePeerconnectionMessage = { ...common, - services: peerconnection.deviceA.config - ? peerconnection.deviceA.config.map(formatServiceConfig) as any + services: peerconnection.deviceA.config?.services + ? peerconnection.deviceA.config.services : [], tiebreaker: false, } const createPeerConnectionMessageB: CreatePeerconnectionMessage = { ...common, - services: peerconnection.deviceB.config - ? peerconnection.deviceB.config.map(formatServiceConfig) as any + services: peerconnection.deviceB.config?.services + ? peerconnection.deviceB.config.services : [], tiebreaker: true, } // TODO: check what problems may occur here and address them accordingly - await apiClient.sendSignalingMessage( + const response1 = apiClient.sendSignalingMessage( peerconnection.deviceA.url, createPeerConnectionMessageA, peerconnectionUrlFromId(peerconnection.uuid) ) - await apiClient.sendSignalingMessage( + const response2 = apiClient.sendSignalingMessage( peerconnection.deviceB.url, createPeerConnectionMessageB, peerconnectionUrlFromId(peerconnection.uuid) ) + await Promise.all([response1, response2]) + // NOTE: this behaviour should maybe be changed later on peerconnection.status = 'connected' await AppDataSource.getRepository(PeerconnectionModel).save(peerconnection) diff --git a/services/device/src/methods/utils.ts b/services/device/src/methods/utils.ts index 78a5a23f..ecd4a7f6 100644 --- a/services/device/src/methods/utils.ts +++ b/services/device/src/methods/utils.ts @@ -1,12 +1,4 @@ import { config } from '../config' -import { - ConcreteDevice, - DeviceGroup, - InstantiableCloudDevice, - InstantiableBrowserDevice, -} from '../generated/types' -import { apiClient } from '../globals' -import { DeviceReferenceModel } from '../model' /** * This function builds the url of a device using its id. @@ -35,54 +27,3 @@ export function peerconnectionUrlFromId(peerconnectionId: string): string { peerconnectionId ) } - -/** - * This function resolves a reference to a device. - * @param reference The reference to be resolved. - * @param flat_group If true then the resolved device group will contain no further device groups. - * @returns The resolved device. - */ -export async function resolveDeviceReference( - reference: DeviceReferenceModel, - flat_group: boolean = false -): Promise< - | ConcreteDevice - | DeviceGroup - | InstantiableCloudDevice - | InstantiableBrowserDevice - | undefined -> { - if (reference.url) { - const deviceId = reference.url.split('/').at(-1) - if (!deviceId) return undefined - console.log('resolving device', reference.url, config.BASE_URL) - try { - return await apiClient.getDevice(reference.url, { flat_group }) - } catch (error) { - return undefined - } - } - - return undefined -} - -/** - * This function flattens a device group. - * @param deviceGroup The device group to be flattened - * @returns The device group containing only concrete devices. - */ -export function flattenDeviceGroup(deviceGroup: DeviceGroup): ConcreteDevice[] { - const devices: ConcreteDevice[] = [] - - if (deviceGroup.devices) { - for (const device of deviceGroup.devices) { - if (!device.type) continue - if (device.type == 'device') devices.push(device) - if (device.type == 'edge instantiable') devices.push(device) - if (device.type == 'cloud instantiable') devices.push(device) - if (device.type == 'group') devices.push(...flattenDeviceGroup(device)) - } - } - - return devices -} diff --git a/services/device/src/model.ts b/services/device/src/model.ts deleted file mode 100644 index ec841b01..00000000 --- a/services/device/src/model.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { - Column, - Entity, - PrimaryGeneratedColumn, - DeleteDateColumn, - OneToMany, - TableInheritance, - ChildEntity, - ManyToOne, - OneToOne, - JoinColumn, - AfterLoad, -} from 'typeorm' - -export function isConcreteDeviceModel( - device: DeviceOverviewModel -): device is ConcreteDeviceModel { - return device.type === 'device' -} - -export function isDeviceGroupModel( - device: DeviceOverviewModel -): device is DeviceGroupModel { - return device.type === 'group' -} - -export function isInstantiableCloudDeviceModel( - device: DeviceOverviewModel -): device is InstantiableCloudDeviceModel { - return device.type === 'cloud instantiable' -} - -export function isInstantiableBrowserDeviceModel( - device: DeviceOverviewModel -): device is InstantiableBrowserDeviceModel { - return device.type === 'edge instantiable' -} - -export function isInstantiableDeviceModel( - device: DeviceOverviewModel -): device is InstantiableBrowserDeviceModel | InstantiableCloudDeviceModel { - return ( - isInstantiableBrowserDeviceModel(device) || isInstantiableCloudDeviceModel(device) - ) -} - -@Entity({ name: 'Device' }) -@TableInheritance({ - column: { - type: 'varchar', - name: 'type', - enum: ['device', 'group', 'cloud instantiable', 'edge instantiable'], - }, -}) -export abstract class DeviceOverviewModel { - @PrimaryGeneratedColumn('uuid') - uuid!: string - @Column() - name?: string - @Column({nullable: true}) - description?: string - @Column() - type?: 'device' | 'group' | 'cloud instantiable' | 'edge instantiable' - @Column() - owner?: string - @DeleteDateColumn() - deletedAt?: Date -} - -@ChildEntity() -export abstract class InstantiableDeviceOverviewModel extends DeviceOverviewModel { - @OneToMany(() => ConcreteDeviceModel, (concreteDevice) => concreteDevice.instanceOf, { - onDelete: 'CASCADE', - cascade: true, - }) - instances?: ConcreteDeviceModel[] -} - -@ChildEntity('device') -export class ConcreteDeviceModel extends DeviceOverviewModel { - @Column() - type?: 'device' - @Column() - connected?: boolean - @OneToMany(() => TimeSlotModel, (timeslot) => timeslot.device, { - onDelete: 'CASCADE', - cascade: true, - }) - announcedAvailability?: TimeSlotModel[] - @OneToMany(() => AvailabilityRuleModel, (timeslot) => timeslot.device, { - onDelete: 'CASCADE', - cascade: true, - }) - availabilityRules?: AvailabilityRuleModel[] - @Column() - experiment?: string - @Column() - token?: string - @OneToMany(() => ServiceModel, (serviceDescription) => serviceDescription.device, { - onDelete: 'CASCADE', - cascade: true, - }) - services?: ServiceModel[] - @ManyToOne( - () => InstantiableDeviceOverviewModel, - (instantiableDevice) => instantiableDevice.instances - ) - instanceOf?: InstantiableDeviceOverviewModel -} - -@ChildEntity('group') -export class DeviceGroupModel extends DeviceOverviewModel { - @Column() - type?: 'group' - @OneToMany(() => DeviceReferenceModel, (deviceReference) => deviceReference.group, { - onDelete: 'CASCADE', - cascade: true, - }) - devices?: DeviceReferenceModel[] -} - -@ChildEntity('cloud instantiable') -export class InstantiableCloudDeviceModel extends InstantiableDeviceOverviewModel { - @Column() - type?: 'cloud instantiable' - @Column() - instantiateUrl?: string -} - -@ChildEntity('edge instantiable') -export class InstantiableBrowserDeviceModel extends InstantiableDeviceOverviewModel { - @Column() - type?: 'edge instantiable' - @Column() - codeUrl?: string -} - -@Entity({ name: 'DeviceReference' }) -export class DeviceReferenceModel { - @PrimaryGeneratedColumn() - id!: number - @Column() - url!: string - @OneToMany(() => ServiceConfigModel, (serviceConfig) => serviceConfig.device, { - onDelete: 'CASCADE', - cascade: true, - }) - config?: ServiceConfigModel[] - @ManyToOne(() => DeviceGroupModel, (deviceGroup) => deviceGroup.devices) - group?: DeviceGroupModel - @DeleteDateColumn() - deletedAt?: Date -} - -@Entity({ name: 'AvailabilityRule' }) -export class AvailabilityRuleModel { - @PrimaryGeneratedColumn() - id!: number - @Column() - available?: boolean - @Column({ nullable: true }) - start?: number - @Column({ nullable: true }) - end?: number - @Column({ nullable: true }) - frequency?: 'HOURLY' | 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY' - @Column({ nullable: true }) - until?: number - @Column({ nullable: true }) - count?: number - @ManyToOne(() => ConcreteDeviceModel, (device) => device.availabilityRules) - device?: ConcreteDeviceModel - @AfterLoad() - nullToUndefined() { - if (this.available == null) this.available = undefined - if (this.start == null) this.start = undefined - if (this.end == null) this.end = undefined - if (this.frequency == null) this.frequency = undefined - if (this.until == null) this.until = undefined - if (this.count == null) this.count = undefined - } - @DeleteDateColumn() - deletedAt?: Date -} - -@Entity({ name: 'TimeSlot' }) -export class TimeSlotModel { - @PrimaryGeneratedColumn() - id!: number - @Column() - start!: number - @Column() - end!: number - @ManyToOne(() => ConcreteDeviceModel, (device) => device.announcedAvailability) - device?: ConcreteDeviceModel - @DeleteDateColumn() - deletedAt?: Date -} - -@Entity({ name: 'Peerconnection' }) -export abstract class PeerconnectionModel { - @PrimaryGeneratedColumn('uuid') - uuid!: string - @Column() - status!: 'waiting-for-devices' | 'connected' | 'failed' | 'closed' - @OneToOne(() => DeviceReferenceModel, { onDelete: 'CASCADE', cascade: true }) - @JoinColumn() - deviceA!: DeviceReferenceModel - @OneToOne(() => DeviceReferenceModel, { onDelete: 'CASCADE', cascade: true }) - @JoinColumn() - deviceB!: DeviceReferenceModel - @DeleteDateColumn() - deletedAt?: Date -} - -@Entity({ name: 'ServiceConfig' }) -export class ServiceConfigModel { - @PrimaryGeneratedColumn() - id!: number - @Column() - serviceType?: string - @Column() - serviceId?: string - @Column() - remoteServiceId?: string - @Column() - config?: string - @ManyToOne(() => DeviceReferenceModel, (deviceReference) => deviceReference.config) - device?: DeviceReferenceModel - @DeleteDateColumn() - deletedAt?: Date -} - -@Entity({ name: 'ServiceDescription' }) -export class ServiceModel { - @PrimaryGeneratedColumn() - id!: number - @Column() - description!: string - @ManyToOne(() => ConcreteDeviceModel, (concreteDevice) => concreteDevice.services) - device?: ConcreteDeviceModel -} diff --git a/services/device/src/operations/devices.ts b/services/device/src/operations/devices.ts deleted file mode 100644 index f3f8584b..00000000 --- a/services/device/src/operations/devices.ts +++ /dev/null @@ -1,387 +0,0 @@ -import { MissingEntityError, ForbiddenOperationError, MissingPropertyError, UnrelatedPeerconnectionError } from "@crosslab/service-common" -import { randomUUID } from "crypto" -import { AppDataSource } from "../data_source" -import { getDevicesSignature, postDevicesSignature, getDevicesByDeviceIdSignature, postDevicesByDeviceIdSignature, deleteDevicesByDeviceIdSignature, patchDevicesByDeviceIdSignature, postDevicesByDeviceIdAvailabilitySignature, postDevicesByDeviceIdWebsocketSignature, postDevicesByDeviceIdSignalingSignature } from "../generated/signatures" -import { ConcreteDevice } from "../generated/types" -import { apiClient, YEAR } from "../globals" -import { applyAvailabilityRules } from "../methods/availability" -import { changedCallbacks, sendChangedCallback } from "../methods/callbacks" -import { createDeviceModelFromDevice } from "../methods/database/create" -import { deleteDeviceModel } from "../methods/database/delete" -import { findDeviceModelByUUID } from "../methods/database/find" -import { formatDeviceOverview, formatDevice, formatTimeSlot } from "../methods/database/format" -import { saveDeviceModel } from "../methods/database/save" -import { writeDevice, writeAvailabilityRule } from "../methods/database/write" -import { deviceUrlFromId } from "../methods/utils" -import { DeviceOverviewModel, isInstantiableDeviceModel, ConcreteDeviceModel, AvailabilityRuleModel } from "../model" -import { connectedDevices } from "./websocket" - -/** - * This function implements the functionality for handling GET requests on /devices endpoint. - * @param _user The user submitting the request. - */ - export const getDevices: getDevicesSignature = async (_user) => { - console.log(`getDevices called`) - const deviceRepository = AppDataSource.getRepository(DeviceOverviewModel) - const devices = await deviceRepository.find() - - console.log(`getDevices succeeded`) - - return { - status: 200, - body: devices.map(formatDeviceOverview), - } -} - -/** - * This function implements the functionality for handling POST requests on /devices endpoint. - * @param parameters The parameters of the request. - * @param body The body of the request. - * @param user The user submitting the request. - */ -export const postDevices: postDevicesSignature = async (parameters, body, user) => { - console.log(`postDevices called`) - - const device = createDeviceModelFromDevice(body) - device.owner = user.JWT?.url - await saveDeviceModel(device) - - if (parameters.changedUrl) { - console.log( - `registering changed-callback for device ${device.uuid} to ${parameters.changedUrl}` - ) - const changedCallbackURLs = changedCallbacks.get(device.uuid) ?? [] - changedCallbackURLs.push(parameters.changedUrl) - changedCallbacks.set(device.uuid, changedCallbackURLs) - } - - console.log(`postDevices succeeded`) - - return { - status: 201, - body: await formatDevice(device), - } -} - -/** - * This function implements the functionality for handling GET requests on /devices/{device_id} endpoint. - * @param parameters The parameters of the request. - * @param _user The user submitting the request. - * @throws {MissingEntityError} Thrown if device is not found in the database. - */ -export const getDevicesByDeviceId: getDevicesByDeviceIdSignature = async ( - parameters, - _user -) => { - console.log(`getDevicesByDeviceId called`) - const device = await findDeviceModelByUUID(parameters.device_id) - - if (!device) - throw new MissingEntityError(`Could not find device ${parameters.device_id}`, 404) - - console.log(`getDevicesByDeviceId succeeded`) - return { - status: 200, - body: await formatDevice(device), - } -} - -/** - * This function implements the functionality for handling POST requests on /devices/{device_id} endpoint. - * @param parameters The parameters of the request. - * @param user The user submitting the request. - * @throws {MissingEntityError} Thrown if device is not found in the database. - * @throws {ForbiddenOperationError} Thrown if device is not instantiable. - */ -export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( - parameters, - user -) => { - console.log(`postDevicesByDeviceId called`) - const instantiableDevice = await findDeviceModelByUUID(parameters.device_id) - - if (!instantiableDevice) - throw new MissingEntityError(`Could not find device ${parameters.device_id}`, 404) - - if (!isInstantiableDeviceModel(instantiableDevice)) - throw new ForbiddenOperationError( - `Cannot create new instance of device ${deviceUrlFromId( - instantiableDevice.uuid - )} since it has type "${instantiableDevice.type}"`, - 400 - ) - - const concreteDevice: ConcreteDevice = { - ...instantiableDevice, - type: 'device', - announcedAvailability: [{ available: true }], - services: [], - } - const concreteDeviceModel = createDeviceModelFromDevice(concreteDevice) - - concreteDeviceModel.owner = user.JWT?.url - await saveDeviceModel(concreteDeviceModel) - - if (parameters.changedUrl) { - console.log( - `registering changed-callback for device ${concreteDevice.uuid} to ${parameters.changedUrl}` - ) - const changedCallbackURLs = changedCallbacks.get(concreteDeviceModel.uuid) ?? [] - changedCallbackURLs.push(parameters.changedUrl) - changedCallbacks.set(concreteDeviceModel.uuid, changedCallbackURLs) - } - - const instance = await formatDevice(concreteDeviceModel) - if (!instance.url) - throw new MissingPropertyError( - 'Created instance of device does not have an url', - 500 - ) - const deviceToken = await apiClient.createDeviceAuthenticationToken(instance.url) // TODO: error handling - if (!instantiableDevice.instances) instantiableDevice.instances = [] - instantiableDevice.instances.push(concreteDeviceModel) - - await saveDeviceModel(instantiableDevice) - - console.log(`postDevicesByDeviceId succeeded`) - - return { - status: 201, - body: { - instance, - deviceToken, - }, - } -} - -/** - * This function implements the functionality for handling DELETE requests on /devices/{device_id} endpoint. - * @param parameters The parameters of the request. - * @param _user The user submitting the request. - * @throws {MissingEntityError} Thrown if device is not found in the database. - */ -export const deleteDevicesByDeviceId: deleteDevicesByDeviceIdSignature = async ( - parameters, - _user -) => { - console.log(`deleteDevicesByDeviceId called`) - const device = await findDeviceModelByUUID(parameters.device_id) - - if (!device) - throw new MissingEntityError(`Could not find device ${parameters.device_id}`, 404) - - await deleteDeviceModel(device) - - console.log(`deleteDevicesByDeviceId succeeded`) - - return { - status: 204, - } -} - -/** - * This function implements the functionality for handling PATCH requests on /devices/{device_id} endpoint. - * @param parameters The parameters of the request. - * @param body The body of the request. - * @param _user The user submitting the request. - * @throws {MissingEntityError} Thrown if device is not found in the database. - * @throws {InvalidChangeError} Thrown if client tries to update the type of the device. - */ -export const patchDevicesByDeviceId: patchDevicesByDeviceIdSignature = async ( - parameters, - body, - _user -) => { - console.log(`patchDevicesByDeviceId called`) - - const device = await findDeviceModelByUUID(parameters.device_id) - - if (!device) - throw new MissingEntityError(`Could not find device ${parameters.device_id}`, 404) - - if (parameters.changedUrl) { - console.log( - `registering changed-callback for device ${device.uuid} to ${parameters.changedUrl}` - ) - const changedCallbackURLs = changedCallbacks.get(device.uuid) ?? [] - changedCallbackURLs.push(parameters.changedUrl) - changedCallbacks.set(device.uuid, changedCallbackURLs) - } - - if (!body || Object.keys(body).length === 0) { - console.log( - `patchDevicesByDeviceId succeeded: no changes applied due to empty body` - ) - return { - status: 200, - body: await formatDevice(device), - } - } - - if (!device.type) { - throw new MissingPropertyError(`Device model is missing a type`) - } - - writeDevice(device, body) - - await sendChangedCallback(device) - - console.log(`patchDevicesByDeviceId succeeded`) - - return { - status: 200, - body: await formatDevice(device), - } -} - -/** - * This function implements the functionality for handling POST requests on /devices/{device_id}/availability endpoint. - * @param parameters The parameters of the request. - * @param body The body of the request. - * @param _user The user submitting the request. - * @throws {MissingEntityError} Thrown if device is not found in the database. - */ -export const postDevicesByDeviceIdAvailability: postDevicesByDeviceIdAvailabilitySignature = - async (parameters, body, _user) => { - console.log(`postDevicesByDeviceIdAvailability called`) - const deviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) - const device = await deviceRepository.findOneBy({ uuid: parameters.device_id }) - - if (!device) - throw new MissingEntityError( - `Could not find device ${parameters.device_id}`, - 404 - ) - - const availabilityRuleRepository = - AppDataSource.getRepository(AvailabilityRuleModel) - - if (!device.availabilityRules) device.availabilityRules = [] - if (body) { - // insert new availability rules - for (const availabilityRule of body) { - const availabilityRuleModel = availabilityRuleRepository.create() - writeAvailabilityRule(availabilityRuleModel, availabilityRule) - device.availabilityRules.push(availabilityRuleModel) - } - } - - device.announcedAvailability = [] - const start = Date.now() - const end = start + YEAR - device.announcedAvailability = applyAvailabilityRules( - device.announcedAvailability, - device.availabilityRules, - start, - end - ) - - await deviceRepository.save(device) - await sendChangedCallback(device) - - console.log(`postDevicesByDeviceIdAvailability succeeded`) - - return { - status: 200, - body: device.announcedAvailability.map(formatTimeSlot), - } - } - -/** - * This function implements the functionality for handling POST requests on /devices/{device_id}/token endpoint. - * @param parameters The parameters of the request. - * @param _user The user submitting the request. - * @throws {MissingEntityError} Thrown if device is not found in the database. - */ -export const postDevicesByDeviceIdWebsocket: postDevicesByDeviceIdWebsocketSignature = async ( - parameters, - _user -) => { - console.log(`postDevicesByDeviceIdToken called`) - const deviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) - const device = await deviceRepository.findOneBy({ uuid: parameters.device_id }) - - if (!device) - throw new MissingEntityError(`Could not find device ${parameters.device_id}`, 404) - - device.token = randomUUID() - await deviceRepository.save(device) - - setTimeout(async () => { - device.token = undefined - await deviceRepository.save(device) - }, 300000) - - console.log(`postDevicesByDeviceIdToken succeeded`) - - return { - status: 200, - body: device.token, - } -} - -/** - * This function implements the functionality for handling POST requests on /devices/{device_id}/signaling endpoint. - * @param parameters The parameters of the request. - * @param body The body of the request. - * @param _user The user submitting the request. - * @throws {MissingEntityError} Thrown if device is not found in the database or if websocket for device is not found. - * @throws {InvalidValueError} Thrown if type of device is not "device" or if device is not part of the peerconnection. - */ -export const postDevicesByDeviceIdSignaling: postDevicesByDeviceIdSignalingSignature = - async (parameters, body, _user) => { - console.log(`postDevicesByDeviceIdSignaling called`) - - // Get device - const device = await findDeviceModelByUUID(parameters.device_id) - if (!device) - throw new MissingEntityError( - `Could not find device ${parameters.device_id}`, - 404 - ) - - // Make sure device is a concrete device - if (device.type !== 'device') - throw new ForbiddenOperationError( - `Cannot send signaling message to device with type ${device.type}`, - 400 - ) - - // Retrieve peerconnection and make sure the device is taking part in it - const peerconnection = await apiClient.getPeerconnection( - parameters.peerconnection_url - ) - if (!peerconnection.devices) - throw new MissingPropertyError( - `Peerconnection does not have any devices`, - 404 - ) - const deviceA = peerconnection.devices[0] - const deviceB = peerconnection.devices[1] - - if ( - !(deviceA.url === deviceUrlFromId(device.uuid)) && - !(deviceB.url === deviceUrlFromId(device.uuid)) - ) { - throw new UnrelatedPeerconnectionError( - `Device is not part of the peerconnection`, - 400 - ) - } - - const ws = connectedDevices.get(parameters.device_id) - - if (!ws) - throw new MissingEntityError( - `Could not find websocket connection for device ${parameters.device_id}`, - 404 - ) - - ws.send(JSON.stringify(body)) - - console.log(`postDevicesByDeviceIdSignaling succeeded`) - - return { - status: 200, - } - } \ No newline at end of file diff --git a/services/device/src/operations/devices/device/availability/index.ts b/services/device/src/operations/devices/device/availability/index.ts new file mode 100644 index 00000000..75a77c0b --- /dev/null +++ b/services/device/src/operations/devices/device/availability/index.ts @@ -0,0 +1 @@ +export * from './post' \ No newline at end of file diff --git a/services/device/src/operations/devices/device/availability/post.ts b/services/device/src/operations/devices/device/availability/post.ts new file mode 100644 index 00000000..7bb254d3 --- /dev/null +++ b/services/device/src/operations/devices/device/availability/post.ts @@ -0,0 +1,51 @@ +import { deviceRepository } from '../../../../database/repositories/device' +import { postDevicesByDeviceIdAvailabilitySignature } from '../../../../generated/signatures' +import { applyAvailabilityRules } from '../../../../methods/availability' +import { sendChangedCallback } from '../../../../methods/callbacks' +import { ForbiddenOperationError } from '@crosslab/service-common' + +const YEAR = 365 * 24 * 60 * 60 * 1000 + +/** + * This function implements the functionality for handling POST requests on /devices/{device_id}/availability endpoint. + * @param parameters The parameters of the request. + * @param body The body of the request. + * @param _user The user submitting the request. + * @throws {MissingEntityError} Thrown if device is not found in the database. + */ +export const postDevicesByDeviceIdAvailability: postDevicesByDeviceIdAvailabilitySignature = + async (parameters, body, _user) => { + console.log(`postDevicesByDeviceIdAvailability called`) + const device = await deviceRepository.findOneOrFail({ + where: { uuid: parameters.device_id }, + }) + + if (device.type !== 'device') { + throw new ForbiddenOperationError( + `Can only the availability for a device of type 'device', not for type '${device.type}'` + ) + } + + device.availabilityRules ??= [] + device.availabilityRules.push(...(body ?? [])) + + device.announcedAvailability = [] + const start = Date.now() + const end = start + YEAR + device.announcedAvailability = applyAvailabilityRules( + device.announcedAvailability, + device.availabilityRules, + start, + end + ) + + await deviceRepository.save(device) + await sendChangedCallback(device) + + console.log(`postDevicesByDeviceIdAvailability succeeded`) + + return { + status: 200, + body: device.announcedAvailability, + } + } diff --git a/services/device/src/operations/devices/device/delete.ts b/services/device/src/operations/devices/device/delete.ts new file mode 100644 index 00000000..44ef6a7f --- /dev/null +++ b/services/device/src/operations/devices/device/delete.ts @@ -0,0 +1,26 @@ +import { deviceRepository } from "../../../database/repositories/device" +import { deleteDevicesByDeviceIdSignature } from "../../../generated/signatures" + +/** + * This function implements the functionality for handling DELETE requests on /devices/{device_id} endpoint. + * @param parameters The parameters of the request. + * @param _user The user submitting the request. + * @throws {MissingEntityError} Thrown if device is not found in the database. + */ +export const deleteDevicesByDeviceId: deleteDevicesByDeviceIdSignature = async ( + parameters, + _user +) => { + console.log(`deleteDevicesByDeviceId called`) + const device = await deviceRepository.findOneOrFail({ + where: { uuid: parameters.device_id }, + }) + + await deviceRepository.remove(device) + + console.log(`deleteDevicesByDeviceId succeeded`) + + return { + status: 204, + } +} \ No newline at end of file diff --git a/services/device/src/operations/devices/device/get.ts b/services/device/src/operations/devices/device/get.ts new file mode 100644 index 00000000..fbeb4831 --- /dev/null +++ b/services/device/src/operations/devices/device/get.ts @@ -0,0 +1,26 @@ +import { deviceRepository } from '../../../database/repositories/device' +import { getDevicesByDeviceIdSignature } from '../../../generated/signatures' + +/** + * This function implements the functionality for handling GET requests on /devices/{device_id} endpoint. + * @param parameters The parameters of the request. + * @param _user The user submitting the request. + * @throws {MissingEntityError} Thrown if device is not found in the database. + */ +export const getDevicesByDeviceId: getDevicesByDeviceIdSignature = async ( + parameters, + _user +) => { + console.log(`getDevicesByDeviceId called`) + const device = await deviceRepository.findOneOrFail({ + where: { uuid: parameters.device_id }, + }) + + console.log(`getDevicesByDeviceId succeeded`) + return { + status: 200, + body: await deviceRepository.format(device, { + flatGroup: parameters.flat_group, + }), + } +} diff --git a/services/device/src/operations/devices/device/index.ts b/services/device/src/operations/devices/device/index.ts new file mode 100644 index 00000000..64fcfffc --- /dev/null +++ b/services/device/src/operations/devices/device/index.ts @@ -0,0 +1,7 @@ +export * from './availability' +export * from './delete' +export * from './get' +export * from './patch' +export * from './post' +export * from './signaling' +export * from './websocket' \ No newline at end of file diff --git a/services/device/src/operations/devices/device/patch.ts b/services/device/src/operations/devices/device/patch.ts new file mode 100644 index 00000000..c15d535e --- /dev/null +++ b/services/device/src/operations/devices/device/patch.ts @@ -0,0 +1,59 @@ +import { MissingPropertyError } from "@crosslab/service-common" +import { deviceRepository } from "../../../database/repositories/device" +import { patchDevicesByDeviceIdSignature } from "../../../generated/signatures" +import { changedCallbacks, sendChangedCallback } from "../../../methods/callbacks" + +/** + * This function implements the functionality for handling PATCH requests on /devices/{device_id} endpoint. + * @param parameters The parameters of the request. + * @param body The body of the request. + * @param _user The user submitting the request. + * @throws {MissingEntityError} Thrown if device is not found in the database. + * @throws {InvalidChangeError} Thrown if client tries to update the type of the device. + */ +export const patchDevicesByDeviceId: patchDevicesByDeviceIdSignature = async ( + parameters, + body, + _user +) => { + console.log(`patchDevicesByDeviceId called`) + + const device = await deviceRepository.findOneOrFail({ + where: { uuid: parameters.device_id }, + }) + + if (parameters.changedUrl) { + console.log( + `registering changed-callback for device ${device.uuid} to ${parameters.changedUrl}` + ) + const changedCallbackURLs = changedCallbacks.get(device.uuid) ?? [] + changedCallbackURLs.push(parameters.changedUrl) + changedCallbacks.set(device.uuid, changedCallbackURLs) + } + + if (!body || Object.keys(body).length === 0) { + console.log( + `patchDevicesByDeviceId succeeded: no changes applied due to empty body` + ) + return { + status: 200, + body: await deviceRepository.format(device), + } + } + + if (!device.type) { + throw new MissingPropertyError(`Device model is missing a type`) + } + + await deviceRepository.write(device, body) + await deviceRepository.save(device) + + await sendChangedCallback(device) + + console.log(`patchDevicesByDeviceId succeeded`) + + return { + status: 200, + body: await deviceRepository.format(device), + } +} \ No newline at end of file diff --git a/services/device/src/operations/devices/device/post.ts b/services/device/src/operations/devices/device/post.ts new file mode 100644 index 00000000..9f480885 --- /dev/null +++ b/services/device/src/operations/devices/device/post.ts @@ -0,0 +1,89 @@ +import { ForbiddenOperationError, InvalidValueError, MissingPropertyError } from "@crosslab/service-common" +import { deviceRepository } from "../../../database/repositories/device" +import { postDevicesByDeviceIdSignature } from "../../../generated/signatures" +import { ConcreteDevice } from "../../../generated/types" +import { apiClient } from "../../../globals" +import { changedCallbacks } from "../../../methods/callbacks" +import { deviceUrlFromId } from "../../../methods/utils" + +/** + * This function implements the functionality for handling POST requests on /devices/{device_id} endpoint. + * @param parameters The parameters of the request. + * @param user The user submitting the request. + * @throws {MissingEntityError} Thrown if device is not found in the database. + * @throws {ForbiddenOperationError} Thrown if device is not instantiable. + */ +export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( + parameters, + user +) => { + console.log(`postDevicesByDeviceId called`) + const instantiableDevice = await deviceRepository.findOneOrFail({ + where: { uuid: parameters.device_id }, + }) + + if ( + instantiableDevice.type !== 'cloud instantiable' && + instantiableDevice.type !== 'edge instantiable' + ) + throw new ForbiddenOperationError( + `Cannot create new instance of device ${deviceUrlFromId( + instantiableDevice.uuid + )} since it has type "${instantiableDevice.type}"`, + 400 + ) + + const concreteDevice: ConcreteDevice = { + services: [], + ...(await deviceRepository.format(instantiableDevice)), + type: 'device', + announcedAvailability: [{ available: true }], + } + const concreteDeviceModel = await deviceRepository.create(concreteDevice) + + if (concreteDeviceModel.type !== 'device') { + throw new InvalidValueError( + `Created instance does not have type 'device', but has type ${concreteDeviceModel.type}` + ) + } + + concreteDeviceModel.owner = user.JWT?.url + await deviceRepository.save(concreteDeviceModel) + + if (parameters.changedUrl) { + console.log( + `registering changed-callback for device ${concreteDevice.uuid} to ${parameters.changedUrl}` + ) + const changedCallbackURLs = changedCallbacks.get(concreteDeviceModel.uuid) ?? [] + changedCallbackURLs.push(parameters.changedUrl) + changedCallbacks.set(concreteDeviceModel.uuid, changedCallbackURLs) + } + + const instance = await deviceRepository.format(concreteDeviceModel) + if (!instance.url) + throw new MissingPropertyError( + 'Created instance of device does not have an url', + 500 + ) + if (instance.type !== 'device') { + throw new InvalidValueError( + `Created instance does not have type 'device', but has type ${concreteDeviceModel.type}` + ) + } + + const deviceToken = await apiClient.createDeviceAuthenticationToken(instance.url) // TODO: error handling + instantiableDevice.instances ??= [] + instantiableDevice.instances.push(concreteDeviceModel) + + await deviceRepository.save(instantiableDevice) + + console.log(`postDevicesByDeviceId succeeded`) + + return { + status: 201, + body: { + deviceToken, + instance: instance, + }, + } +} \ No newline at end of file diff --git a/services/device/src/operations/devices/device/signaling/index.ts b/services/device/src/operations/devices/device/signaling/index.ts new file mode 100644 index 00000000..75a77c0b --- /dev/null +++ b/services/device/src/operations/devices/device/signaling/index.ts @@ -0,0 +1 @@ +export * from './post' \ No newline at end of file diff --git a/services/device/src/operations/devices/device/signaling/post.ts b/services/device/src/operations/devices/device/signaling/post.ts new file mode 100644 index 00000000..519c47c0 --- /dev/null +++ b/services/device/src/operations/devices/device/signaling/post.ts @@ -0,0 +1,69 @@ +import { ForbiddenOperationError, MissingPropertyError, UnrelatedPeerconnectionError, MissingEntityError } from "@crosslab/service-common" +import { deviceRepository } from "../../../../database/repositories/device" +import { postDevicesByDeviceIdSignalingSignature } from "../../../../generated/signatures" +import { apiClient } from "../../../../globals" +import { deviceUrlFromId } from "../../../../methods/utils" +import { connectedDevices } from "../../../websocket" + +/** + * This function implements the functionality for handling POST requests on /devices/{device_id}/signaling endpoint. + * @param parameters The parameters of the request. + * @param body The body of the request. + * @param _user The user submitting the request. + * @throws {MissingEntityError} Thrown if device is not found in the database or if websocket for device is not found. + * @throws {InvalidValueError} Thrown if type of device is not "device" or if device is not part of the peerconnection. + */ +export const postDevicesByDeviceIdSignaling: postDevicesByDeviceIdSignalingSignature = + async (parameters, body, _user) => { + console.log(`postDevicesByDeviceIdSignaling called`) + + // Get device + const device = await deviceRepository.findOneOrFail({ + where: { uuid: parameters.device_id }, + }) + + // Make sure device is a concrete device + if (device.type !== 'device') + throw new ForbiddenOperationError( + `Cannot send signaling message to device with type ${device.type}`, + 400 + ) + + // Retrieve peerconnection and make sure the device is taking part in it + const peerconnection = await apiClient.getPeerconnection( + parameters.peerconnection_url + ) + if (!peerconnection.devices) + throw new MissingPropertyError( + `Peerconnection does not have any devices`, + 404 + ) + const deviceA = peerconnection.devices[0] + const deviceB = peerconnection.devices[1] + + if ( + !(deviceA.url === deviceUrlFromId(device.uuid)) && + !(deviceB.url === deviceUrlFromId(device.uuid)) + ) { + throw new UnrelatedPeerconnectionError( + `Device is not part of the peerconnection`, + 400 + ) + } + + const ws = connectedDevices.get(parameters.device_id) + + if (!ws) + throw new MissingEntityError( + `Could not find websocket connection for device ${parameters.device_id}`, + 404 + ) + + ws.send(JSON.stringify(body)) + + console.log(`postDevicesByDeviceIdSignaling succeeded`) + + return { + status: 200, + } + } \ No newline at end of file diff --git a/services/device/src/operations/devices/device/websocket/index.ts b/services/device/src/operations/devices/device/websocket/index.ts new file mode 100644 index 00000000..75a77c0b --- /dev/null +++ b/services/device/src/operations/devices/device/websocket/index.ts @@ -0,0 +1 @@ +export * from './post' \ No newline at end of file diff --git a/services/device/src/operations/devices/device/websocket/post.ts b/services/device/src/operations/devices/device/websocket/post.ts new file mode 100644 index 00000000..f9d08fb9 --- /dev/null +++ b/services/device/src/operations/devices/device/websocket/post.ts @@ -0,0 +1,39 @@ +import { MissingEntityError } from "@crosslab/service-common" +import { randomUUID } from "crypto" +import { AppDataSource } from "../../../../database/dataSource" +import { ConcreteDeviceModel } from "../../../../database/model" +import { postDevicesByDeviceIdWebsocketSignature } from "../../../../generated/signatures" + +/** + * This function implements the functionality for handling POST requests on /devices/{device_id}/token endpoint. + * @param parameters The parameters of the request. + * @param _user The user submitting the request. + * @throws {MissingEntityError} Thrown if device is not found in the database. + */ +export const postDevicesByDeviceIdWebsocket: postDevicesByDeviceIdWebsocketSignature = + async (parameters, _user) => { + console.log(`postDevicesByDeviceIdToken called`) + const deviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) + const device = await deviceRepository.findOneBy({ uuid: parameters.device_id }) + + if (!device) + throw new MissingEntityError( + `Could not find device ${parameters.device_id}`, + 404 + ) + + device.token = randomUUID() + await deviceRepository.save(device) + + setTimeout(async () => { + device.token = undefined + await deviceRepository.save(device) + }, 300000) + + console.log(`postDevicesByDeviceIdToken succeeded`) + + return { + status: 200, + body: device.token, + } + } \ No newline at end of file diff --git a/services/device/src/operations/devices/get.ts b/services/device/src/operations/devices/get.ts new file mode 100644 index 00000000..6bdf4744 --- /dev/null +++ b/services/device/src/operations/devices/get.ts @@ -0,0 +1,18 @@ +import { deviceRepository } from '../../database/repositories/device' +import { getDevicesSignature } from '../../generated/signatures' + +/** + * This function implements the functionality for handling GET requests on /devices endpoint. + * @param _user The user submitting the request. + */ +export const getDevices: getDevicesSignature = async (_user) => { + console.log(`getDevices called`) + const devices = await deviceRepository.find() + + console.log(`getDevices succeeded`) + + return { + status: 200, + body: await Promise.all(devices.map(deviceRepository.formatOverview)), + } +} diff --git a/services/device/src/operations/devices/index.ts b/services/device/src/operations/devices/index.ts new file mode 100644 index 00000000..0ce71aa1 --- /dev/null +++ b/services/device/src/operations/devices/index.ts @@ -0,0 +1,3 @@ +export * from './device' +export * from './get' +export * from './post' diff --git a/services/device/src/operations/devices/post.ts b/services/device/src/operations/devices/post.ts new file mode 100644 index 00000000..3c8d551b --- /dev/null +++ b/services/device/src/operations/devices/post.ts @@ -0,0 +1,33 @@ +import { deviceRepository } from "../../database/repositories/device" +import { postDevicesSignature } from "../../generated/signatures" +import { changedCallbacks } from "../../methods/callbacks" + +/** + * This function implements the functionality for handling POST requests on /devices endpoint. + * @param parameters The parameters of the request. + * @param body The body of the request. + * @param user The user submitting the request. + */ +export const postDevices: postDevicesSignature = async (parameters, body, user) => { + console.log(`postDevices called`) + + const device = await deviceRepository.create(body) + device.owner = user.JWT?.url + await deviceRepository.save(device) + + if (parameters.changedUrl) { + console.log( + `registering changed-callback for device ${device.uuid} to ${parameters.changedUrl}` + ) + const changedCallbackURLs = changedCallbacks.get(device.uuid) ?? [] + changedCallbackURLs.push(parameters.changedUrl) + changedCallbacks.set(device.uuid, changedCallbackURLs) + } + + console.log(`postDevices succeeded`) + + return { + status: 201, + body: await deviceRepository.format(device), + } +} \ No newline at end of file diff --git a/services/device/src/operations/peerconnections.ts b/services/device/src/operations/peerconnections.ts deleted file mode 100644 index e0604d8c..00000000 --- a/services/device/src/operations/peerconnections.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { MissingEntityError, InvalidValueError, MissingPropertyError, InconsistentDatabaseError } from "@crosslab/service-common" -import { AppDataSource } from "../data_source" -import { getPeerconnectionsSignature, postPeerconnectionsSignature, getPeerconnectionsByPeerconnectionIdSignature, deletePeerconnectionsByPeerconnectionIdSignature } from "../generated/signatures" -import { ClosePeerconnectionMessage } from "../generated/types" -import { apiClient, timeoutMap } from "../globals" -import { callbackUrl, sendStatusChangedCallback, closedCallbacks, statusChangedCallbacks, sendClosedCallback } from "../methods/callbacks" -import { formatPeerconnectionOverview } from "../methods/database/format" -import { writePeerconnection } from "../methods/database/write" -import { startSignaling } from "../methods/signaling" -import { peerconnectionUrlFromId } from "../methods/utils" -import { PeerconnectionModel } from "../model" - -/** - * This function implements the functionality for handling GET requests on /peerconnections endpoint. - * @param _user The user submitting the request. - */ - export const getPeerconnections: getPeerconnectionsSignature = async (_user) => { - console.log(`getPeerconnections called`) - const peerconnectionRepository = AppDataSource.getRepository(PeerconnectionModel) - const peerconnections = await peerconnectionRepository.find({ - relations: { - deviceA: true, - deviceB: true, - }, - }) - - console.log(`getPeerconnections succeeded`) - - return { - status: 200, - body: peerconnections.map(formatPeerconnectionOverview), - } -} - -/** - * This function implements the functionality for handling POST requests on /peerconnections endpoint. - * @param parameters The parameters of the request. - * @param body The body of the request. - * @param _user The user submitting the request. - */ -export const postPeerconnections: postPeerconnectionsSignature = async ( - parameters, - body, - _user -) => { - console.log(`postPeerconnections called`) - const peerconnectionRepository = AppDataSource.getRepository(PeerconnectionModel) - const peerconnection = peerconnectionRepository.create() - await writePeerconnection(peerconnection, body) - - if (!peerconnection.deviceA.url || !peerconnection.deviceB.url) { - throw new MissingEntityError(`One of the participating devices has no url`, 404) - } - - await peerconnectionRepository.save(peerconnection) - - const deviceA = await apiClient.getDevice(peerconnection.deviceA.url) - const deviceB = await apiClient.getDevice(peerconnection.deviceB.url) - - if (deviceA.type !== 'device' || deviceB.type !== 'device') { - throw new InvalidValueError( - `Cannot establish a peerconnection between devices of type "${deviceA.type}" and "${deviceB.type}"`, - 400 - ) - } - - if (!deviceA.url || !deviceB.url) { - throw new MissingPropertyError( - `One of the resolved devices does not have an url`, - 500 - ) // NOTE: error code - } - - if (deviceA.connected && deviceB.connected) { - // peerconnection can be started directly - await startSignaling(peerconnection) - } else { - // need to wait for devices to connect - // register changed callbacks for devices to get notified when they connect - const n_deviceA = await apiClient.updateDevice( - deviceA.url, - {}, - { changedUrl: callbackUrl } - ) - const n_deviceB = await apiClient.updateDevice( - deviceB.url, - {}, - { changedUrl: callbackUrl } - ) - - // check that devices still have the correct type - if (n_deviceA.type !== 'device' || n_deviceB.type !== 'device') { - throw new InvalidValueError( - `The type of device ${ - deviceA.type !== 'device' ? deviceA.url : deviceB.url - } is not "device" anymore`, - 400 - ) - } - - // set timeout for checking if devices are connected - timeoutMap.set( - peerconnection.uuid, - setTimeout(async () => { - console.log('devices did not connect') - peerconnection.status = 'failed' - await peerconnectionRepository.save(peerconnection) - await sendStatusChangedCallback(peerconnection) - }, 30000) - ) - } - - if (parameters.closedUrl) { - console.log( - `postPeerconnections: registering closed-callback for ${parameters.closedUrl}` - ) - const closedCallbackURLs = closedCallbacks.get(peerconnection.uuid) ?? [] - closedCallbackURLs.push(parameters.closedUrl) - closedCallbacks.set(peerconnection.uuid, closedCallbackURLs) - } - - if (parameters.statusChangedUrl) { - console.log( - `postPeerconnections: registering status-changed-callback for ${parameters.statusChangedUrl}` - ) - const statusChangedCallbackURLs = - statusChangedCallbacks.get(peerconnection.uuid) ?? [] - statusChangedCallbackURLs.push(parameters.statusChangedUrl) - statusChangedCallbacks.set(peerconnection.uuid, statusChangedCallbackURLs) - } - - console.log(`postPeerconnections succeeded`) - - return { - status: peerconnection.status === 'connected' ? 201 : 202, - body: formatPeerconnectionOverview(peerconnection), - } -} - -/** - * This function implements the functionality for handling GET requests on /peerconnections/{peerconnection_id} endpoint. - * @param parameters The parameters of the request. - * @param _user The user submitting the request. - */ -export const getPeerconnectionsByPeerconnectionId: getPeerconnectionsByPeerconnectionIdSignature = - async (parameters, _user) => { - console.log(`getPeerconnectionsByPeerconnectionId called`) - const peerconnectionRepository = AppDataSource.getRepository(PeerconnectionModel) - const peerconnection = await peerconnectionRepository.findOne({ - where: { - uuid: parameters.peerconnection_id, - }, - relations: { - deviceA: true, - deviceB: true, - }, - }) - - if (!peerconnection) - throw new MissingEntityError( - `Could not find peerconnection ${parameters.peerconnection_id}`, - 404 - ) - - console.log(`getPeerconnectionsByPeerconnectionId succeeded`) - - return { - status: 200, - body: formatPeerconnectionOverview(peerconnection), - } - } - -/** - * This function implements the functionality for handling DELETE requests on /peerconnection/{peerconnection_id} endpoint. - * @param parameters The parameters of the request. - * @param _user The user submitting the request. - */ -export const deletePeerconnectionsByPeerconnectionId: deletePeerconnectionsByPeerconnectionIdSignature = - async (parameters, _user) => { - console.log(`deletePeerconnectionsByPeerconnectionId called`) - const peerconnectionRepository = AppDataSource.getRepository(PeerconnectionModel) - const peerconnection = await peerconnectionRepository.findOneOrFail({ - where: { - uuid: parameters.peerconnection_id, - }, - relations: { - deviceA: true, - deviceB: true, - }, - }) - const result = await peerconnectionRepository.softDelete({ - uuid: parameters.peerconnection_id, - }) - - if (!result.affected) { - throw new MissingEntityError( - `Could not find peerconnection ${parameters.peerconnection_id}`, - 404 - ) - } - - if (result.affected > 1) { - throw new InconsistentDatabaseError( - 'Deleted Multiple Peerconnections with same uuid', - 500 - ) - } - - const closePeerconnectionMessage: ClosePeerconnectionMessage = { - messageType: 'command', - command: 'closePeerconnection', - connectionUrl: peerconnectionUrlFromId(peerconnection.uuid), - } - - await apiClient.sendSignalingMessage( - peerconnection.deviceA.url, - closePeerconnectionMessage, - peerconnectionUrlFromId(peerconnection.uuid) - ) - await apiClient.sendSignalingMessage( - peerconnection.deviceB.url, - closePeerconnectionMessage, - peerconnectionUrlFromId(peerconnection.uuid) - ) - - await sendClosedCallback(peerconnection) - - console.log(`deletePeerconnectionsByPeerconnectionId succeeded`) - - return { - status: 204, - } - } \ No newline at end of file diff --git a/services/device/src/operations/peerconnections/get.ts b/services/device/src/operations/peerconnections/get.ts new file mode 100644 index 00000000..eaffdb69 --- /dev/null +++ b/services/device/src/operations/peerconnections/get.ts @@ -0,0 +1,18 @@ +import { peerconnectionRepository } from '../../database/repositories/peerconnection' +import { getPeerconnectionsSignature } from '../../generated/signatures' + +/** + * This function implements the functionality for handling GET requests on /peerconnections endpoint. + * @param _user The user submitting the request. + */ +export const getPeerconnections: getPeerconnectionsSignature = async (_user) => { + console.log(`getPeerconnections called`) + const peerconnections = await peerconnectionRepository.find() + + console.log(`getPeerconnections succeeded`) + + return { + status: 200, + body: peerconnections.map(peerconnectionRepository.formatOverview), + } +} diff --git a/services/device/src/operations/peerconnections/index.ts b/services/device/src/operations/peerconnections/index.ts new file mode 100644 index 00000000..136c26ae --- /dev/null +++ b/services/device/src/operations/peerconnections/index.ts @@ -0,0 +1,3 @@ +export * from './peerconnection' +export * from './get' +export * from './post' diff --git a/services/device/src/operations/peerconnections/peerconnection/delete.ts b/services/device/src/operations/peerconnections/peerconnection/delete.ts new file mode 100644 index 00000000..d30d3efd --- /dev/null +++ b/services/device/src/operations/peerconnections/peerconnection/delete.ts @@ -0,0 +1,52 @@ +import { peerconnectionRepository } from '../../../database/repositories/peerconnection' +import { deletePeerconnectionsByPeerconnectionIdSignature } from '../../../generated/signatures' +import { ClosePeerconnectionMessage } from '../../../generated/types' +import { apiClient } from '../../../globals' +import { sendClosedCallback } from '../../../methods/callbacks' +import { peerconnectionUrlFromId } from '../../../methods/utils' + +/** + * This function implements the functionality for handling DELETE requests on /peerconnection/{peerconnection_id} endpoint. + * @param parameters The parameters of the request. + * @param _user The user submitting the request. + */ +export const deletePeerconnectionsByPeerconnectionId: deletePeerconnectionsByPeerconnectionIdSignature = + async (parameters, _user) => { + console.log(`deletePeerconnectionsByPeerconnectionId called`) + + const peerconnection = await peerconnectionRepository.findOneOrFail({ + where: { uuid: parameters.peerconnection_id }, + }) + + await peerconnectionRepository.remove(peerconnection) + + if (peerconnection.status === 'connected') { + const closePeerconnectionMessage: ClosePeerconnectionMessage = { + messageType: 'command', + command: 'closePeerconnection', + connectionUrl: peerconnectionUrlFromId(peerconnection.uuid), + } + + if (peerconnection.deviceA.url && peerconnection.deviceB.url) { + await apiClient.sendSignalingMessage( + peerconnection.deviceA.url, + closePeerconnectionMessage, + peerconnectionUrlFromId(peerconnection.uuid) + ) + + await apiClient.sendSignalingMessage( + peerconnection.deviceB.url, + closePeerconnectionMessage, + peerconnectionUrlFromId(peerconnection.uuid) + ) + } + + await sendClosedCallback(peerconnection) + } + + console.log(`deletePeerconnectionsByPeerconnectionId succeeded`) + + return { + status: 204, + } + } diff --git a/services/device/src/operations/peerconnections/peerconnection/get.ts b/services/device/src/operations/peerconnections/peerconnection/get.ts new file mode 100644 index 00000000..c8c932ca --- /dev/null +++ b/services/device/src/operations/peerconnections/peerconnection/get.ts @@ -0,0 +1,23 @@ +import { peerconnectionRepository } from '../../../database/repositories/peerconnection' +import { getPeerconnectionsByPeerconnectionIdSignature } from '../../../generated/signatures' + +/** + * This function implements the functionality for handling GET requests on /peerconnections/{peerconnection_id} endpoint. + * @param parameters The parameters of the request. + * @param _user The user submitting the request. + */ +export const getPeerconnectionsByPeerconnectionId: getPeerconnectionsByPeerconnectionIdSignature = + async (parameters, _user) => { + console.log(`getPeerconnectionsByPeerconnectionId called`) + + const peerconnection = await peerconnectionRepository.findOneOrFail({ + where: { uuid: parameters.peerconnection_id }, + }) + + console.log(`getPeerconnectionsByPeerconnectionId succeeded`) + + return { + status: 200, + body: await peerconnectionRepository.format(peerconnection), + } + } diff --git a/services/device/src/operations/peerconnections/peerconnection/index.ts b/services/device/src/operations/peerconnections/peerconnection/index.ts new file mode 100644 index 00000000..4109217b --- /dev/null +++ b/services/device/src/operations/peerconnections/peerconnection/index.ts @@ -0,0 +1,2 @@ +export * from './delete' +export * from './get' diff --git a/services/device/src/operations/peerconnections/post.ts b/services/device/src/operations/peerconnections/post.ts new file mode 100644 index 00000000..9549c69a --- /dev/null +++ b/services/device/src/operations/peerconnections/post.ts @@ -0,0 +1,119 @@ +import { peerconnectionRepository } from '../../database/repositories/peerconnection' +import { postPeerconnectionsSignature } from '../../generated/signatures' +import { apiClient, timeoutMap } from '../../globals' +import { + callbackUrl, + sendStatusChangedCallback, + closedCallbacks, + statusChangedCallbacks, +} from '../../methods/callbacks' +import { signalingQueue } from '../../methods/signaling' +import { + MissingEntityError, + InvalidValueError, + MissingPropertyError, +} from '@crosslab/service-common' + +/** + * This function implements the functionality for handling POST requests on /peerconnections endpoint. + * @param parameters The parameters of the request. + * @param body The body of the request. + * @param _user The user submitting the request. + */ +export const postPeerconnections: postPeerconnectionsSignature = async ( + parameters, + body, + _user +) => { + console.log(`postPeerconnections called`) + + const peerconnection = await peerconnectionRepository.create(body) + + if (!peerconnection.deviceA.url || !peerconnection.deviceB.url) { + throw new MissingEntityError(`One of the participating devices has no url`, 404) + } + + await peerconnectionRepository.save(peerconnection) + + const deviceA = await apiClient.getDevice(peerconnection.deviceA.url) + const deviceB = await apiClient.getDevice(peerconnection.deviceB.url) + + if (deviceA.type !== 'device' || deviceB.type !== 'device') { + throw new InvalidValueError( + `Cannot establish a peerconnection between devices of type "${deviceA.type}" and "${deviceB.type}"`, + 400 + ) + } + + if (!deviceA.url || !deviceB.url) { + throw new MissingPropertyError( + `One of the resolved devices does not have an url`, + 500 + ) // NOTE: error code + } + + if (deviceA.connected && deviceB.connected) { + // peerconnection can be started directly + signalingQueue.addPeerconnection(peerconnection) + } else { + // need to wait for devices to connect + // register changed callbacks for devices to get notified when they connect + const n_deviceA = await apiClient.updateDevice( + deviceA.url, + {}, + { changedUrl: callbackUrl } + ) + const n_deviceB = await apiClient.updateDevice( + deviceB.url, + {}, + { changedUrl: callbackUrl } + ) + + // check that devices still have the correct type + if (n_deviceA.type !== 'device' || n_deviceB.type !== 'device') { + throw new InvalidValueError( + `The type of device ${ + deviceA.type !== 'device' ? deviceA.url : deviceB.url + } is not "device" anymore`, + 400 + ) + } + + // set timeout for checking if devices are connected + timeoutMap.set( + peerconnection.uuid, + setTimeout(async () => { + console.log('devices did not connect') + peerconnection.status = 'failed' + await peerconnectionRepository.save(peerconnection) + await sendStatusChangedCallback(peerconnection) + }, 30000) + ) + } + + if (parameters.closedUrl) { + console.log( + `postPeerconnections: registering closed-callback for ${parameters.closedUrl}` + ) + const closedCallbackURLs = closedCallbacks.get(peerconnection.uuid) ?? [] + closedCallbackURLs.push(parameters.closedUrl) + closedCallbacks.set(peerconnection.uuid, closedCallbackURLs) + } + + if (parameters.statusChangedUrl) { + console.log( + `postPeerconnections: registering status-changed-callback for ${parameters.statusChangedUrl}` + ) + const statusChangedCallbackURLs = + statusChangedCallbacks.get(peerconnection.uuid) ?? [] + statusChangedCallbackURLs.push(parameters.statusChangedUrl) + statusChangedCallbacks.set(peerconnection.uuid, statusChangedCallbackURLs) + } + + console.log(`postPeerconnections succeeded`) + + return { + status: peerconnection.status === 'connected' ? 201 : 202, + body: await peerconnectionRepository.format(peerconnection), + } +} diff --git a/services/device/src/operations/websocket.ts b/services/device/src/operations/websocket.ts index 7b4077ba..72586491 100644 --- a/services/device/src/operations/websocket.ts +++ b/services/device/src/operations/websocket.ts @@ -1,9 +1,13 @@ -import WebSocket from "ws" -import { AppDataSource } from "../data_source" -import { isMessage, isAuthenticationMessage, AuthenticationMessage } from "../generated/types" -import { sendChangedCallback } from "../methods/callbacks" -import { handleDeviceMessage } from "../methods/messageHandling" -import { ConcreteDeviceModel } from "../model" +import { AppDataSource } from '../database/dataSource' +import { ConcreteDeviceModel } from '../database/model' +import { + isMessage, + isAuthenticationMessage, + AuthenticationMessage, +} from '../generated/types' +import { sendChangedCallback } from '../methods/callbacks' +import { handleDeviceMessage } from '../methods/messageHandling' +import WebSocket from 'ws' export const connectedDevices = new Map() @@ -11,7 +15,7 @@ export const connectedDevices = new Map() * This function adds the /devices/ws endpoint, including its functionality, to an express application. * @param app The express application to add the /devices/ws endpoint to. */ - export function deviceHandling(app: Express.Application) { +export function deviceHandling(app: Express.Application) { // TODO: close Peerconnections that have device as participant when websocket connection is closed? app.ws('/devices/websocket', (ws) => { // authenticate and start heartbeat @@ -19,22 +23,32 @@ export const connectedDevices = new Map() // device authentication and connection const deviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) const message = JSON.parse(data.toString('utf8')) + if (!(isMessage(message) && isAuthenticationMessage(message))) { ws.close(1002, 'Received message is not an authentication message') return } + if (!message.token) { - ws.close(1002, 'Authentication message does not contain a valid websocket token') + ws.close( + 1002, + 'Authentication message does not contain a valid websocket token' + ) } - const device = await deviceRepository.findOne({ where: { token: message.token } }) + + const device = await deviceRepository.findOne({ + where: { token: message.token }, + }) if (!device) { ws.close(1002, 'No device found with matching websocket token') return } + if (device.token != message.token) { ws.close(1002, 'Provided token does not match the token of the device') return } + device.connected = true connectedDevices.set(device.uuid, ws) await deviceRepository.save(device) @@ -87,4 +101,4 @@ export const connectedDevices = new Map() }) }) }) -} \ No newline at end of file +} diff --git a/services/device/src/types/device.ts b/services/device/src/types/device.ts new file mode 100644 index 00000000..f33fe715 --- /dev/null +++ b/services/device/src/types/device.ts @@ -0,0 +1,24 @@ +import { + ConcreteDeviceModel, + DeviceGroupModel, + InstantiableBrowserDeviceModel, + InstantiableCloudDeviceModel, +} from '../database/model' +import { + ConcreteDevice, + DeviceGroup, + InstantiableBrowserDevice, + InstantiableCloudDevice, +} from '../generated/types' + +export type Device = + | ConcreteDevice + | DeviceGroup + | InstantiableBrowserDevice + | InstantiableCloudDevice + +export type DeviceModel = + | ConcreteDeviceModel + | DeviceGroupModel + | InstantiableBrowserDeviceModel + | InstantiableCloudDeviceModel diff --git a/services/device/src/types/errors.ts b/services/device/src/types/errors.ts deleted file mode 100644 index 66ff02dd..00000000 --- a/services/device/src/types/errors.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { ErrorWithStatus } from '../generated/types' - -/** - * This error class should be used if an entity is not found in the database. - */ -export class MissingEntityError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'MissingEntityError' - } -} - -/** - * This error class should be used if an object is missing a needed property. - */ -export class MissingPropertyError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'MissingPropertyError' - } -} - -/** - * This error class should be used if a device is not related to a peerconnection. - */ -export class UnrelatedPeerconnectionError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'UnrelatedPeerconnectionError' - } -} - -/** - * This error class should be used if an object is missing a needed property. - */ -export class ForbiddenOperationError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'ForbiddenOperationError' - } -} - -/** - * This error class should be used if an object contains an invalid value. - */ -export class InvalidValueError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'InvalidValueError' - } -} - -/** - * This error class should be used if there is an inconsistency in the database. - */ -export class InconsistentDatabaseError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'InconsistentDatabaseError' - } -} - -/** - * This error class should be used if the user attempts an invalid change. - */ -export class InvalidChangeError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'InvalidChangeError' - } -} - -/** - * This error class should be used if a required device is not connection. - */ -export class DeviceNotConnectedError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'DeviceNotConnectedError' - } -} - -/** - * This error class should be used if an error occurs during JWT verification. - */ - export class JWTVerificationError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = "JWTVerificationError" - } -} - -/** - * This error class should be used if the body of a request is malformed. - */ - export class MalformedBodyError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = "MalformedBodyError" - } -} \ No newline at end of file diff --git a/services/device/src/types/helper.ts b/services/device/src/types/helper.ts deleted file mode 100644 index 1c44058e..00000000 --- a/services/device/src/types/helper.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { - ConcreteDevice, - DeviceGroup, - InstantiableBrowserDevice, - InstantiableCloudDevice, - AvailabilityRule, -} from '../generated/types' -import { - ConcreteDeviceModel, - DeviceGroupModel, - InstantiableBrowserDeviceModel, - InstantiableCloudDeviceModel, -} from '../model' - -export type DeviceTypeName = - | 'device' - | 'group' - | 'edge instantiable' - | 'cloud instantiable' -export type Device = - | ConcreteDevice - | DeviceGroup - | InstantiableBrowserDevice - | InstantiableCloudDevice -export type DeviceModel = - | ConcreteDeviceModel - | DeviceGroupModel - | InstantiableBrowserDeviceModel - | InstantiableCloudDeviceModel - -export type DeviceFromName = T extends 'device' - ? ConcreteDevice - : T extends 'group' - ? DeviceGroup - : T extends 'edge instantiable' - ? InstantiableBrowserDevice - : T extends 'cloud instantiable' - ? InstantiableCloudDevice - : never - -export type DeviceModelFromName = T extends 'device' - ? ConcreteDeviceModel - : T extends 'group' - ? DeviceGroupModel - : T extends 'edge instantiable' - ? InstantiableBrowserDeviceModel - : T extends 'cloud instantiable' - ? InstantiableCloudDeviceModel - : never - -export type DeviceFromModel = T extends ConcreteDeviceModel - ? ConcreteDevice - : T extends DeviceGroupModel - ? DeviceGroup - : T extends InstantiableBrowserDeviceModel - ? InstantiableBrowserDevice - : T extends InstantiableCloudDeviceModel - ? InstantiableCloudDevice - : never - -export type WriteDeviceFromModel = T extends ConcreteDeviceModel - ? ConcreteDevice & { announcedAvailability?: AvailabilityRule[] } - : T extends DeviceGroupModel - ? DeviceGroup - : T extends InstantiableBrowserDeviceModel - ? InstantiableBrowserDevice - : T extends InstantiableCloudDeviceModel - ? InstantiableCloudDevice - : never From 34c453eecdb6e89368459d81c8c4cf434cb60857 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 20 Mar 2023 19:27:20 +0100 Subject: [PATCH 04/33] Add new tuple handling for type generation --- .../.vscode/settings.json | 3 + .../src/filters/typescript/typings.ts | 15 +++- .../templates/service/signatures.ts.njk | 49 ++----------- .../templates/service/types.ts.njk | 71 +++++++++++++++++++ 4 files changed, 91 insertions(+), 47 deletions(-) diff --git a/helper/crosslab-typescript-addon/.vscode/settings.json b/helper/crosslab-typescript-addon/.vscode/settings.json index f90817be..1a2d8d88 100644 --- a/helper/crosslab-typescript-addon/.vscode/settings.json +++ b/helper/crosslab-typescript-addon/.vscode/settings.json @@ -29,5 +29,8 @@ "**/node_modules": true, "**/venv": true, //end generated + }, + "[njk]": { + "editor.formatOnSave": false } } diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts b/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts index ba808f1e..936c31a8 100644 --- a/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts +++ b/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts @@ -1,6 +1,6 @@ /* eslint-disable no-case-declarations */ -import { OpenAPIV3_1 } from 'openapi-types' import { formatName } from './format' +import { OpenAPIV3_1 } from 'openapi-types' /** * Interface for the property of a destructured schema. @@ -278,8 +278,19 @@ export function schemaToTypeDeclaration( (schema as OpenAPIV3_1.ArraySchemaObject).items, options ) + + let min = 'undefined' + let max = 'undefined' + + if (schema.minItems) min = schema.minItems.toString() + if (schema.maxItems) max = schema.maxItems.toString() + + if (schema.minItems && schema.maxItems && schema.minItems > schema.maxItems) { + throw new Error('minItems needs to be smaller than maxItems!') + } + return { - typeDeclaration: `${td.typeDeclaration}[]`, + typeDeclaration: `SizedTuple<${td.typeDeclaration},${min},${max}>`, typeDependencies: td.typeDependencies, comment: comment, } diff --git a/helper/crosslab-typescript-addon/templates/service/signatures.ts.njk b/helper/crosslab-typescript-addon/templates/service/signatures.ts.njk index cea5fcae..47833be6 100644 --- a/helper/crosslab-typescript-addon/templates/service/signatures.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service/signatures.ts.njk @@ -119,7 +119,7 @@ export type {{ operation.name }}ErrorResponseType = {{ error_responses | join(" * Typing for a response with status {{ response.status }} to a {{ operation.method | upper }} request on {{ operation.path }} */ export interface {{ operation.name }}{{ response.status }}ResponseType extends {{ "SuccessResponse" if response.status | int < 400 else "ErrorResponse" }} { - status: {{ ("Status" + response.status) if (response.status | endswith("XX")) else response.status }} + status: {{ ("NumericRange<" + (response.status | replace("XX", "00")) + "," + (response.status | replace("XX", "00") | int + 100) + ">") if (response.status | endswith("XX")) else response.status }} headers{{ "?" if not response.headers }}: { {% for header in response.headers -%} "{{ header.name }}"{{ "?" if not header.required}}: {{ header.schema | typeDeclaration(schemas, { "schemaType": "response" }) | indent(8) if header.schema else "undefined" }}, @@ -169,51 +169,10 @@ export interface {{ operation.name }}{{ response.status }}ResponseType extends { * and run openapi-codegeneration to regenerate this file. */ import { - {{ "Require," if signatures | includes("Require<") }} + {{- "\n\tSizedTuple," if signatures | includes("SizedTuple<") }} + {{- "\n\tRequire," if signatures | includes("Require<") }} + {{- "\n\tNumericRange," if signatures | includes("NumericRange<") }} {{ typeDependencies | flatten | unique | join(",\n\t") }} } from "./types" -{%- set hasStatus1XX = false -%} -{%- set hasStatus2XX = false -%} -{%- set hasStatus3XX = false -%} -{%- set hasStatus4XX = false -%} -{%- set hasStatus5XX = false -%} - -{%- for operation in operations -%} - {%- for response in operation.responses -%} - {%- if response.status == "1XX" -%} - {%- set hasStatus1XX = true -%} - {%- elif response.status == "2XX" -%} - {%- set hasStatus2XX = true -%} - {%- elif response.status == "3XX" -%} - {%- set hasStatus3XX = true -%} - {%- elif response.status == "4XX" -%} - {%- set hasStatus4XX = true -%} - {%- elif response.status == "5XX" -%} - {%- set hasStatus5XX = true -%} - {%- endif -%} - {%- endfor -%} -{%- endfor -%} - -{%- if hasStatus1XX %} - -type Status1XX = {{ range(100,200) | join("|") }} -{%- endif %} -{%- if hasStatus2XX %} -{{- "\n" if not (hasStatus1XX)}} -type Status2XX = {{ range(200,300) | join("|") }} -{%- endif %} -{%- if hasStatus3XX %} -{{- "\n" if not (hasStatus1XX and hasStatus2XX)}} -type Status3XX = {{ range(300,400) | join("|") }} -{%- endif %} -{%- if hasStatus4XX %} -{{- "\n" if not (hasStatus1XX and hasStatus2XX and hasStatus3XX)}} -type Status4XX = {{ range(400,500) | join("|") }} -{%- endif %} -{%- if hasStatus5XX %} -{{- "\n" if not (hasStatus1XX and hasStatus2XX and hasStatus3XX and hasStatus4XX)}} -type Status5XX = {{ range(500,600) | join("|") }} -{%- endif %} - {{ signatures | prettier }} \ No newline at end of file diff --git a/helper/crosslab-typescript-addon/templates/service/types.ts.njk b/helper/crosslab-typescript-addon/templates/service/types.ts.njk index 8d49c7a0..0de586d7 100644 --- a/helper/crosslab-typescript-addon/templates/service/types.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service/types.ts.njk @@ -94,6 +94,77 @@ export type Require = Partial & { [Property in Key]-?: Type[Property] } +export type SizedTuple< + T, + MIN extends number | undefined = undefined, + MAX extends number | undefined = undefined +> = MIN extends number + ? MAX extends number + ? _SizedTuple> + : TupleObject> & T[] + : MAX extends number + ? _SizedTuple, true> + : T[]; + +type _SizedTuple< + T, + ARR extends number[], + Z extends boolean = false +> = ARR extends [infer HEAD extends number, ...infer TAIL extends number[]] + ? Tuple | _SizedTuple + : never; + +type Tuple = _Tuple< + T, + NumericRangeTuple +>; + +type _Tuple = N extends [ + infer HEAD, + ...infer TAIL extends number[] +] + ? HEAD extends 0 + ? [] | _Tuple + : [T, ..._Tuple] + : []; + +type TupleObject = N extends [ + infer HEAD extends number, + ...infer TAIL extends number[] +] + ? TAIL extends [] + ? {} + : { [P in HEAD]: T } & TupleObject + : {}; + +export type NumericRange< + START extends number, + END extends number, + ARR extends unknown[] = [], + ACC extends number = never +> = ARR['length'] extends END + ? ACC | START | END + : NumericRange< + START, + END, + [...ARR, 1], + ARR[START] extends undefined ? ACC : ACC | ARR['length'] + >; + +type NumericRangeTuple< + START extends number, + END extends number, + ARR extends unknown[] = [], + ACC extends number[] = [] +> = ARR['length'] extends END + ? [START, ...ACC, END] + : NumericRangeTuple< + START, + END, + [...ARR, 1], + ARR[START] extends undefined ? ACC : [...ACC, ARR['length']] + >; + {{ schemas | standaloneTypings }} {%- for schema in schemas | selectattr("x-typeguard") | select("attrequalto", ["x-standalone", true]) | select("attrequalto", ["x-schema-type", "all"]) %} From ee0a06416e92c9531aeacefa8ed18d6b4583dc1b Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 20 Mar 2023 19:28:19 +0100 Subject: [PATCH 05/33] Further refactoring & tests folder structure - Change API folder structure (WIP) - Create test folder structure - Move callback routes to operations - Move websocket routes into device operations - Make small changes to API (e.g. required type on device creation) --- services/device/api/content/availability.yml | 2 +- .../api/content/availability_request.yml | 2 +- services/device/api/content/device_body.yml | 14 +- .../device/api/content/device_concrete.yml | 2 +- .../api/content/device_concrete_event.yml | 2 +- services/device/api/content/device_event.yml | 8 +- .../api/content/device_instantiated.yml | 2 +- services/device/api/content/device_list.yml | 2 +- .../device/api/content/device_response.yml | 6 +- .../device/api/content/peerconnection.yml | 2 +- .../content/peerconnection_closed_event.yml | 2 +- .../api/content/peerconnection_list.yml | 2 +- .../peerconnection_status_changed_event.yml | 2 +- .../availability}/availability.yml | 2 +- .../availability}/availability_rule.yml | 0 .../{ => devices/availability}/time_slot.yml | 0 .../configured_device_reference.yml | 4 +- .../api/schemas/{ => devices}/device.yml | 0 .../device_cloud_instantiable.yml | 3 +- .../schemas/{ => devices}/device_concrete.yml | 5 +- .../device_edge_instantiable.yml | 3 +- .../schemas/{ => devices}/device_group.yml | 0 .../api/schemas/devices/device_init.yml | 35 ++ .../schemas/{ => devices}/device_overview.yml | 0 .../{ => devices}/device_reference.yml | 0 .../{ => devices/services}/service_config.yml | 0 .../services}/service_description.yml | 0 .../create_peerconnection_message.yml | 2 +- .../{ => peerconnections}/peerconnection.yml | 5 +- .../peerconnection_common.yml} | 7 - .../peerconnection_overview.yml | 12 + services/device/dist/openapi.json | 356 ++++++++++-------- services/device/package-lock.json | 13 + services/device/package.json | 1 + services/device/src/config.ts | 1 - services/device/src/database/model.ts | 6 + .../src/database/repositories/device.ts | 4 +- .../repositories/device/deviceGroup.ts | 3 +- .../repositories/device/deviceOverview.ts | 2 +- .../database/repositories/peerconnection.ts | 3 +- services/device/src/index.ts | 6 +- services/device/src/methods/availability.ts | 280 +++++++------- services/device/src/methods/callbacks.ts | 169 +-------- services/device/src/methods/signaling.ts | 2 +- .../src/methods/{utils.ts => urlFromId.ts} | 0 .../callbacks/event/deviceChanged.ts | 85 +++++ .../src/operations/callbacks/event/index.ts | 33 ++ .../device/src/operations/callbacks/index.ts | 51 +++ .../src/operations/devices/device/patch.ts | 10 +- .../src/operations/devices/device/post.ts | 20 +- .../devices/device/signaling/post.ts | 19 +- .../device/src/operations/devices/index.ts | 1 + .../device/src/operations/devices/post.ts | 8 +- .../websocket/index.ts} | 12 +- .../devices/websocket}/messageHandling.ts | 8 +- services/device/src/operations/index.ts | 2 + .../peerconnections/peerconnection/delete.ts | 2 +- services/device/src/types/device.ts | 24 -- services/device/test/config.spec.ts | 0 services/device/test/data/device.spec.ts | 32 ++ services/device/test/data/index.spec.ts | 19 + .../device/test/data/peerconnection.spec.ts | 41 ++ .../device/test/database/dataSource.spec.ts | 0 services/device/test/database/index.spec.ts | 0 services/device/test/database/model.spec.ts | 0 .../test/database/repositories/device.spec.ts | 90 +++++ .../test/database/repositories/index.spec.ts | 70 ++++ .../repositories/peerconnection.spec.ts | 66 ++++ services/device/test/index.spec.ts | 0 .../device/test/methods/availability.spec.ts | 0 .../device/test/methods/callbacks.spec.ts | 0 services/device/test/methods/index.spec.ts | 0 .../device/test/methods/signaling.spec.ts | 0 .../device/test/methods/urlFromId.spec.ts | 0 .../callbacks/event/deviceChanged.spec.ts | 0 .../operations/callbacks/event/index.spec.ts | 0 .../test/operations/callbacks/index.spec.ts | 0 .../devices/device/availability/index.spec.ts | 0 .../devices/device/availability/post.spec.ts | 0 .../operations/devices/device/delete.spec.ts | 0 .../operations/devices/device/get.spec.ts | 0 .../operations/devices/device/index.spec.ts | 0 .../operations/devices/device/patch.spec.ts | 0 .../operations/devices/device/post.spec.ts | 0 .../devices/device/signaling/index.spec.ts | 0 .../devices/device/signaling/post.spec.ts | 0 .../devices/device/websocket/index.spec.ts | 0 .../devices/device/websocket/post.spec.ts | 0 .../test/operations/devices/get.spec.ts | 0 .../test/operations/devices/index.spec.ts | 0 .../test/operations/devices/post.spec.ts | 0 .../devices/websocket/index.spec.ts | 0 .../devices/websocket/messageHandling.spec.ts | 0 services/device/test/operations/index.spec.ts | 0 .../operations/peerconnections/get.spec.ts | 0 .../operations/peerconnections/index.spec.ts | 0 .../peerconnection/delete.spec.ts | 0 .../peerconnection/get.spec.ts | 0 .../peerconnection/index.spec.ts | 0 .../operations/peerconnections/post.spec.ts | 0 services/device/tsconfig.json | 24 +- 101 files changed, 995 insertions(+), 594 deletions(-) rename services/device/api/schemas/{ => devices/availability}/availability.yml (86%) rename services/device/api/schemas/{ => devices/availability}/availability_rule.yml (100%) rename services/device/api/schemas/{ => devices/availability}/time_slot.yml (100%) rename services/device/api/schemas/{ => devices}/configured_device_reference.yml (82%) rename services/device/api/schemas/{ => devices}/device.yml (100%) rename services/device/api/schemas/{ => devices}/device_cloud_instantiable.yml (85%) rename services/device/api/schemas/{ => devices}/device_concrete.yml (84%) rename services/device/api/schemas/{ => devices}/device_edge_instantiable.yml (85%) rename services/device/api/schemas/{ => devices}/device_group.yml (100%) create mode 100644 services/device/api/schemas/devices/device_init.yml rename services/device/api/schemas/{ => devices}/device_overview.yml (100%) rename services/device/api/schemas/{ => devices}/device_reference.yml (100%) rename services/device/api/schemas/{ => devices/services}/service_config.yml (100%) rename services/device/api/schemas/{ => devices/services}/service_description.yml (100%) rename services/device/api/schemas/{ => peerconnections}/peerconnection.yml (78%) rename services/device/api/schemas/{peerconnection_overview.yml => peerconnections/peerconnection_common.yml} (69%) create mode 100644 services/device/api/schemas/peerconnections/peerconnection_overview.yml rename services/device/src/methods/{utils.ts => urlFromId.ts} (100%) create mode 100644 services/device/src/operations/callbacks/event/deviceChanged.ts create mode 100644 services/device/src/operations/callbacks/event/index.ts create mode 100644 services/device/src/operations/callbacks/index.ts rename services/device/src/operations/{websocket.ts => devices/websocket/index.ts} (91%) rename services/device/src/{methods => operations/devices/websocket}/messageHandling.ts (90%) delete mode 100644 services/device/src/types/device.ts create mode 100644 services/device/test/config.spec.ts create mode 100644 services/device/test/data/device.spec.ts create mode 100644 services/device/test/data/index.spec.ts create mode 100644 services/device/test/data/peerconnection.spec.ts create mode 100644 services/device/test/database/dataSource.spec.ts create mode 100644 services/device/test/database/index.spec.ts create mode 100644 services/device/test/database/model.spec.ts create mode 100644 services/device/test/database/repositories/device.spec.ts create mode 100644 services/device/test/database/repositories/index.spec.ts create mode 100644 services/device/test/database/repositories/peerconnection.spec.ts create mode 100644 services/device/test/index.spec.ts create mode 100644 services/device/test/methods/availability.spec.ts create mode 100644 services/device/test/methods/callbacks.spec.ts create mode 100644 services/device/test/methods/index.spec.ts create mode 100644 services/device/test/methods/signaling.spec.ts create mode 100644 services/device/test/methods/urlFromId.spec.ts create mode 100644 services/device/test/operations/callbacks/event/deviceChanged.spec.ts create mode 100644 services/device/test/operations/callbacks/event/index.spec.ts create mode 100644 services/device/test/operations/callbacks/index.spec.ts create mode 100644 services/device/test/operations/devices/device/availability/index.spec.ts create mode 100644 services/device/test/operations/devices/device/availability/post.spec.ts create mode 100644 services/device/test/operations/devices/device/delete.spec.ts create mode 100644 services/device/test/operations/devices/device/get.spec.ts create mode 100644 services/device/test/operations/devices/device/index.spec.ts create mode 100644 services/device/test/operations/devices/device/patch.spec.ts create mode 100644 services/device/test/operations/devices/device/post.spec.ts create mode 100644 services/device/test/operations/devices/device/signaling/index.spec.ts create mode 100644 services/device/test/operations/devices/device/signaling/post.spec.ts create mode 100644 services/device/test/operations/devices/device/websocket/index.spec.ts create mode 100644 services/device/test/operations/devices/device/websocket/post.spec.ts create mode 100644 services/device/test/operations/devices/get.spec.ts create mode 100644 services/device/test/operations/devices/index.spec.ts create mode 100644 services/device/test/operations/devices/post.spec.ts create mode 100644 services/device/test/operations/devices/websocket/index.spec.ts create mode 100644 services/device/test/operations/devices/websocket/messageHandling.spec.ts create mode 100644 services/device/test/operations/index.spec.ts create mode 100644 services/device/test/operations/peerconnections/get.spec.ts create mode 100644 services/device/test/operations/peerconnections/index.spec.ts create mode 100644 services/device/test/operations/peerconnections/peerconnection/delete.spec.ts create mode 100644 services/device/test/operations/peerconnections/peerconnection/get.spec.ts create mode 100644 services/device/test/operations/peerconnections/peerconnection/index.spec.ts create mode 100644 services/device/test/operations/peerconnections/post.spec.ts mode change 120000 => 100644 services/device/tsconfig.json diff --git a/services/device/api/content/availability.yml b/services/device/api/content/availability.yml index 4bf47fb3..5e99e6c3 100644 --- a/services/device/api/content/availability.yml +++ b/services/device/api/content/availability.yml @@ -1,3 +1,3 @@ # yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json schema: - $ref: ../schemas/availability.yml + $ref: ../schemas/devices/availability/availability.yml diff --git a/services/device/api/content/availability_request.yml b/services/device/api/content/availability_request.yml index 06244556..a5e96f48 100644 --- a/services/device/api/content/availability_request.yml +++ b/services/device/api/content/availability_request.yml @@ -4,7 +4,7 @@ schema: description: The availability rule to be applied. type: array items: - $ref: "../schemas/availability_rule.yml" + $ref: "../schemas/devices/availability/availability_rule.yml" examples: make_the_device_always_unavailable: description: Make the device always unavailable diff --git a/services/device/api/content/device_body.yml b/services/device/api/content/device_body.yml index 07586651..3289f4cd 100644 --- a/services/device/api/content/device_body.yml +++ b/services/device/api/content/device_body.yml @@ -1,18 +1,6 @@ # yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json schema: - title: Device Init - anyOf: - - allOf: - - $ref: '../schemas/device_concrete.yml' - - type: object - properties: - announcedAvailability: - type: array - items: - $ref: "../schemas/availability_rule.yml" - - $ref: '../schemas/device_group.yml' - - $ref: '../schemas/device_cloud_instantiable.yml' - - $ref: '../schemas/device_edge_instantiable.yml' + $ref: ../schemas/devices/device_init.yml examples: microcontroller: value: diff --git a/services/device/api/content/device_concrete.yml b/services/device/api/content/device_concrete.yml index bbd10f49..fc40abc7 100644 --- a/services/device/api/content/device_concrete.yml +++ b/services/device/api/content/device_concrete.yml @@ -1,3 +1,3 @@ # yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json schema: - $ref: '../schemas/device_concrete.yml' \ No newline at end of file + $ref: '../schemas/devices/device_concrete.yml' \ No newline at end of file diff --git a/services/device/api/content/device_concrete_event.yml b/services/device/api/content/device_concrete_event.yml index 10dedf7d..2a7fc97a 100644 --- a/services/device/api/content/device_concrete_event.yml +++ b/services/device/api/content/device_concrete_event.yml @@ -11,4 +11,4 @@ schema: enum: - device-changed device: - $ref: "../schemas/device_concrete.yml" + $ref: "../schemas/devices/device_concrete.yml" diff --git a/services/device/api/content/device_event.yml b/services/device/api/content/device_event.yml index 02a0b57e..942c6cb4 100644 --- a/services/device/api/content/device_event.yml +++ b/services/device/api/content/device_event.yml @@ -12,7 +12,7 @@ schema: - device-changed device: anyOf: - - $ref: "../schemas/device_concrete.yml" - - $ref: "../schemas/device_group.yml" - - $ref: '../schemas/device_cloud_instantiable.yml' - - $ref: '../schemas/device_edge_instantiable.yml' + - $ref: "../schemas/devices/device_concrete.yml" + - $ref: "../schemas/devices/device_group.yml" + - $ref: '../schemas/devices/device_cloud_instantiable.yml' + - $ref: '../schemas/devices/device_edge_instantiable.yml' diff --git a/services/device/api/content/device_instantiated.yml b/services/device/api/content/device_instantiated.yml index ed74b9ea..6e52259a 100644 --- a/services/device/api/content/device_instantiated.yml +++ b/services/device/api/content/device_instantiated.yml @@ -3,6 +3,6 @@ schema: type: object properties: instance: - $ref: '../schemas/device_concrete.yml' + $ref: '../schemas/devices/device_concrete.yml' deviceToken: type: string \ No newline at end of file diff --git a/services/device/api/content/device_list.yml b/services/device/api/content/device_list.yml index 7d6f8029..e2f8454b 100644 --- a/services/device/api/content/device_list.yml +++ b/services/device/api/content/device_list.yml @@ -2,4 +2,4 @@ schema: type: array items: - $ref: '../schemas/device_overview.yml' \ No newline at end of file + $ref: '../schemas/devices/device_overview.yml' \ No newline at end of file diff --git a/services/device/api/content/device_response.yml b/services/device/api/content/device_response.yml index e9e0d26c..1fb04f58 100644 --- a/services/device/api/content/device_response.yml +++ b/services/device/api/content/device_response.yml @@ -1,10 +1,6 @@ # yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json schema: - anyOf: - - $ref: '../schemas/device_concrete.yml' - - $ref: '../schemas/device_group.yml' - - $ref: '../schemas/device_cloud_instantiable.yml' - - $ref: '../schemas/device_edge_instantiable.yml' + $ref: ../schemas/devices/device.yml examples: microcontroller: value: diff --git a/services/device/api/content/peerconnection.yml b/services/device/api/content/peerconnection.yml index 8d9eee45..5de755b0 100644 --- a/services/device/api/content/peerconnection.yml +++ b/services/device/api/content/peerconnection.yml @@ -1,3 +1,3 @@ # yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json schema: - $ref: '../schemas/peerconnection.yml' \ No newline at end of file + $ref: '../schemas/peerconnections/peerconnection.yml' \ No newline at end of file diff --git a/services/device/api/content/peerconnection_closed_event.yml b/services/device/api/content/peerconnection_closed_event.yml index 9e13295f..86d9dce2 100644 --- a/services/device/api/content/peerconnection_closed_event.yml +++ b/services/device/api/content/peerconnection_closed_event.yml @@ -11,4 +11,4 @@ schema: enum: - peerconnection-closed peerconnection: - $ref: '../schemas/peerconnection.yml' \ No newline at end of file + $ref: '../schemas/peerconnections/peerconnection.yml' \ No newline at end of file diff --git a/services/device/api/content/peerconnection_list.yml b/services/device/api/content/peerconnection_list.yml index 3670e101..44ab4350 100644 --- a/services/device/api/content/peerconnection_list.yml +++ b/services/device/api/content/peerconnection_list.yml @@ -2,4 +2,4 @@ schema: type: array items: - $ref: '../schemas/peerconnection_overview.yml' \ No newline at end of file + $ref: '../schemas/peerconnections/peerconnection_overview.yml' \ No newline at end of file diff --git a/services/device/api/content/peerconnection_status_changed_event.yml b/services/device/api/content/peerconnection_status_changed_event.yml index 8b268ab3..b4ad33c3 100644 --- a/services/device/api/content/peerconnection_status_changed_event.yml +++ b/services/device/api/content/peerconnection_status_changed_event.yml @@ -11,4 +11,4 @@ schema: enum: - peerconnection-status-changed peerconnection: - $ref: '../schemas/peerconnection.yml' \ No newline at end of file + $ref: '../schemas/peerconnections/peerconnection.yml' \ No newline at end of file diff --git a/services/device/api/schemas/availability.yml b/services/device/api/schemas/devices/availability/availability.yml similarity index 86% rename from services/device/api/schemas/availability.yml rename to services/device/api/schemas/devices/availability/availability.yml index bba30b74..8a41e51f 100644 --- a/services/device/api/schemas/availability.yml +++ b/services/device/api/schemas/devices/availability/availability.yml @@ -4,4 +4,4 @@ description: | A list of time slots that the maintainer of the device announced it is available type: array items: - $ref: ../schemas/time_slot.yml + $ref: ./time_slot.yml diff --git a/services/device/api/schemas/availability_rule.yml b/services/device/api/schemas/devices/availability/availability_rule.yml similarity index 100% rename from services/device/api/schemas/availability_rule.yml rename to services/device/api/schemas/devices/availability/availability_rule.yml diff --git a/services/device/api/schemas/time_slot.yml b/services/device/api/schemas/devices/availability/time_slot.yml similarity index 100% rename from services/device/api/schemas/time_slot.yml rename to services/device/api/schemas/devices/availability/time_slot.yml diff --git a/services/device/api/schemas/configured_device_reference.yml b/services/device/api/schemas/devices/configured_device_reference.yml similarity index 82% rename from services/device/api/schemas/configured_device_reference.yml rename to services/device/api/schemas/devices/configured_device_reference.yml index 112ffb5a..1019eb47 100644 --- a/services/device/api/schemas/configured_device_reference.yml +++ b/services/device/api/schemas/devices/configured_device_reference.yml @@ -12,4 +12,6 @@ properties: services: type: array items: - $ref: './service_config.yml' \ No newline at end of file + $ref: './services/service_config.yml' +required: + - url \ No newline at end of file diff --git a/services/device/api/schemas/device.yml b/services/device/api/schemas/devices/device.yml similarity index 100% rename from services/device/api/schemas/device.yml rename to services/device/api/schemas/devices/device.yml diff --git a/services/device/api/schemas/device_cloud_instantiable.yml b/services/device/api/schemas/devices/device_cloud_instantiable.yml similarity index 85% rename from services/device/api/schemas/device_cloud_instantiable.yml rename to services/device/api/schemas/devices/device_cloud_instantiable.yml index ebdcc9e4..06467303 100644 --- a/services/device/api/schemas/device_cloud_instantiable.yml +++ b/services/device/api/schemas/devices/device_cloud_instantiable.yml @@ -12,6 +12,5 @@ allOf: services: type: array items: - type: object - additionalProperties: true + $ref: ./services/service_description.yml x-typeguard: true diff --git a/services/device/api/schemas/device_concrete.yml b/services/device/api/schemas/devices/device_concrete.yml similarity index 84% rename from services/device/api/schemas/device_concrete.yml rename to services/device/api/schemas/devices/device_concrete.yml index 5dcbce2c..49cd6f03 100644 --- a/services/device/api/schemas/device_concrete.yml +++ b/services/device/api/schemas/devices/device_concrete.yml @@ -12,7 +12,7 @@ allOf: type: boolean readOnly: true announcedAvailability: - $ref: "../schemas/availability.yml" + $ref: "./availability/availability.yml" readOnly: true experiment: type: string @@ -20,6 +20,5 @@ allOf: services: type: array items: - type: object - additionalProperties: true + $ref: ./services/service_description.yml x-typeguard: true diff --git a/services/device/api/schemas/device_edge_instantiable.yml b/services/device/api/schemas/devices/device_edge_instantiable.yml similarity index 85% rename from services/device/api/schemas/device_edge_instantiable.yml rename to services/device/api/schemas/devices/device_edge_instantiable.yml index 3cf5d323..8e3ff43f 100644 --- a/services/device/api/schemas/device_edge_instantiable.yml +++ b/services/device/api/schemas/devices/device_edge_instantiable.yml @@ -12,6 +12,5 @@ allOf: services: type: array items: - type: object - additionalProperties: true + $ref: ./services/service_description.yml x-typeguard: true diff --git a/services/device/api/schemas/device_group.yml b/services/device/api/schemas/devices/device_group.yml similarity index 100% rename from services/device/api/schemas/device_group.yml rename to services/device/api/schemas/devices/device_group.yml diff --git a/services/device/api/schemas/devices/device_init.yml b/services/device/api/schemas/devices/device_init.yml new file mode 100644 index 00000000..d748206f --- /dev/null +++ b/services/device/api/schemas/devices/device_init.yml @@ -0,0 +1,35 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Device Init +anyOf: + - allOf: + - $ref: './device_concrete.yml' + - type: object + properties: + type: + const: device + required: + - type + - allOf: + - $ref: './device_group.yml' + - type: object + properties: + type: + const: group + required: + - type + - allOf: + - $ref: './device_cloud_instantiable.yml' + - type: object + properties: + type: + const: cloud instantiable + required: + - type + - allOf: + - $ref: './device_edge_instantiable.yml' + - type: object + properties: + type: + const: edge instantiable + required: + - type \ No newline at end of file diff --git a/services/device/api/schemas/device_overview.yml b/services/device/api/schemas/devices/device_overview.yml similarity index 100% rename from services/device/api/schemas/device_overview.yml rename to services/device/api/schemas/devices/device_overview.yml diff --git a/services/device/api/schemas/device_reference.yml b/services/device/api/schemas/devices/device_reference.yml similarity index 100% rename from services/device/api/schemas/device_reference.yml rename to services/device/api/schemas/devices/device_reference.yml diff --git a/services/device/api/schemas/service_config.yml b/services/device/api/schemas/devices/services/service_config.yml similarity index 100% rename from services/device/api/schemas/service_config.yml rename to services/device/api/schemas/devices/services/service_config.yml diff --git a/services/device/api/schemas/service_description.yml b/services/device/api/schemas/devices/services/service_description.yml similarity index 100% rename from services/device/api/schemas/service_description.yml rename to services/device/api/schemas/devices/services/service_description.yml diff --git a/services/device/api/schemas/messages/create_peerconnection_message.yml b/services/device/api/schemas/messages/create_peerconnection_message.yml index 7f329808..f54b0362 100644 --- a/services/device/api/schemas/messages/create_peerconnection_message.yml +++ b/services/device/api/schemas/messages/create_peerconnection_message.yml @@ -19,7 +19,7 @@ allOf: type: array items: type: object - $ref: "../service_config.yml" + $ref: "../devices/services/service_config.yml" required: - serviceType - serviceId diff --git a/services/device/api/schemas/peerconnection.yml b/services/device/api/schemas/peerconnections/peerconnection.yml similarity index 78% rename from services/device/api/schemas/peerconnection.yml rename to services/device/api/schemas/peerconnections/peerconnection.yml index f1d14ec2..380e5dcc 100644 --- a/services/device/api/schemas/peerconnection.yml +++ b/services/device/api/schemas/peerconnections/peerconnection.yml @@ -1,7 +1,7 @@ # yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema title: Peerconnection allOf: - - $ref: ./peerconnection_overview.yml + - $ref: ./peerconnection_common.yml - type: object properties: devices: @@ -9,10 +9,11 @@ allOf: minItems: 2 maxItems: 2 items: - $ref: "./configured_device_reference.yml" + $ref: "../devices/configured_device_reference.yml" status: type: string description: The status of the peerconnection. + readOnly: true enum: - waiting-for-devices - connected diff --git a/services/device/api/schemas/peerconnection_overview.yml b/services/device/api/schemas/peerconnections/peerconnection_common.yml similarity index 69% rename from services/device/api/schemas/peerconnection_overview.yml rename to services/device/api/schemas/peerconnections/peerconnection_common.yml index 8929bf91..5295f831 100644 --- a/services/device/api/schemas/peerconnection_overview.yml +++ b/services/device/api/schemas/peerconnections/peerconnection_common.yml @@ -1,5 +1,4 @@ # yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -title: Peerconnection Overview type: object properties: url: @@ -7,12 +6,6 @@ properties: description: URL of the peerconnection format: uri readOnly: true - devices: - type: array - minItems: 2 - maxItems: 2 - items: - $ref: "./device_reference.yml" type: type: string description: Type of the peerconnection diff --git a/services/device/api/schemas/peerconnections/peerconnection_overview.yml b/services/device/api/schemas/peerconnections/peerconnection_overview.yml new file mode 100644 index 00000000..e5eeb93d --- /dev/null +++ b/services/device/api/schemas/peerconnections/peerconnection_overview.yml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Peerconnection Overview +allOf: + - $ref: ./peerconnection_common.yml + - type: object + properties: + devices: + type: array + minItems: 2 + maxItems: 2 + items: + $ref: "../devices/device_reference.yml" \ No newline at end of file diff --git a/services/device/dist/openapi.json b/services/device/dist/openapi.json index 7ddf09f3..317b53cc 100644 --- a/services/device/dist/openapi.json +++ b/services/device/dist/openapi.json @@ -103,6 +103,28 @@ "$ref": "#/components/schemas/time_slot" } }, + "service_description": { + "title": "Service Description", + "type": "object", + "properties": { + "serviceType": { + "type": "string", + "format": "uri" + }, + "serviceId": { + "type": "string" + }, + "serviceDirection": { + "type": "string", + "enum": [ + "consumer", + "producer", + "prosumer" + ] + } + }, + "additionalProperties": true + }, "device_concrete": { "title": "Concrete Device", "allOf": [ @@ -131,8 +153,7 @@ "services": { "type": "array", "items": { - "type": "object", - "additionalProperties": true + "$ref": "#/components/schemas/service_description" } } } @@ -140,48 +161,6 @@ ], "x-typeguard": true }, - "availability_rule": { - "title": "Availability Rule", - "type": "object", - "allOf": [ - { - "$ref": "#/components/schemas/time_slot" - }, - { - "type": "object", - "properties": { - "available": { - "type": "boolean" - }, - "repeat": { - "description": "If specified the time slot is repeated in a fixed offset specified by the frequency", - "type": "object", - "properties": { - "frequency": { - "type": "string", - "enum": [ - "HOURLY", - "DAILY", - "WEEKLY", - "MONTHLY", - "YEARLY" - ] - }, - "until": { - "description": "Up to this date-time the time slot will be repeated.", - "type": "string", - "format": "date-time" - }, - "count": { - "description": "How often the time slot will be repeated", - "type": "integer" - } - } - } - } - } - ] - }, "device_reference": { "title": "Device Reference", "type": "object", @@ -238,8 +217,7 @@ "services": { "type": "array", "items": { - "type": "object", - "additionalProperties": true + "$ref": "#/components/schemas/service_description" } } } @@ -266,8 +244,7 @@ "services": { "type": "array", "items": { - "type": "object", - "additionalProperties": true + "$ref": "#/components/schemas/service_description" } } } @@ -275,6 +252,142 @@ ], "x-typeguard": true }, + "device_init": { + "title": "Device Init", + "anyOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/device_concrete" + }, + { + "type": "object", + "properties": { + "type": { + "const": "device" + } + }, + "required": [ + "type" + ] + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/device_group" + }, + { + "type": "object", + "properties": { + "type": { + "const": "group" + } + }, + "required": [ + "type" + ] + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/device_cloud_instantiable" + }, + { + "type": "object", + "properties": { + "type": { + "const": "cloud instantiable" + } + }, + "required": [ + "type" + ] + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/device_edge_instantiable" + }, + { + "type": "object", + "properties": { + "type": { + "const": "edge instantiable" + } + }, + "required": [ + "type" + ] + } + ] + } + ] + }, + "device": { + "title": "Device", + "oneOf": [ + { + "$ref": "#/components/schemas/device_cloud_instantiable" + }, + { + "$ref": "#/components/schemas/device_concrete" + }, + { + "$ref": "#/components/schemas/device_edge_instantiable" + }, + { + "$ref": "#/components/schemas/device_group" + } + ] + }, + "availability_rule": { + "title": "Availability Rule", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/time_slot" + }, + { + "type": "object", + "properties": { + "available": { + "type": "boolean" + }, + "repeat": { + "description": "If specified the time slot is repeated in a fixed offset specified by the frequency", + "type": "object", + "properties": { + "frequency": { + "type": "string", + "enum": [ + "HOURLY", + "DAILY", + "WEEKLY", + "MONTHLY", + "YEARLY" + ] + }, + "until": { + "description": "Up to this date-time the time slot will be repeated.", + "type": "string", + "format": "date-time" + }, + "count": { + "description": "How often the time slot will be repeated", + "type": "integer" + } + } + } + } + } + ] + }, "message": { "title": "Message", "type": "object", @@ -454,8 +567,7 @@ ], "x-typeguard": true }, - "peerconnection_overview": { - "title": "Peerconnection Overview", + "peerconnection_common": { "type": "object", "properties": { "url": { @@ -464,14 +576,6 @@ "format": "uri", "readOnly": true }, - "devices": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": { - "$ref": "#/components/schemas/device_reference" - } - }, "type": { "type": "string", "description": "Type of the peerconnection", @@ -482,6 +586,27 @@ } } }, + "peerconnection_overview": { + "title": "Peerconnection Overview", + "allOf": [ + { + "$ref": "#/components/schemas/peerconnection_common" + }, + { + "type": "object", + "properties": { + "devices": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "$ref": "#/components/schemas/device_reference" + } + } + } + } + ] + }, "configured_device_reference": { "title": "Configured Device Reference", "type": "object", @@ -502,13 +627,16 @@ } } } - } + }, + "required": [ + "url" + ] }, "peerconnection": { "title": "Peerconnection", "allOf": [ { - "$ref": "#/components/schemas/peerconnection_overview" + "$ref": "#/components/schemas/peerconnection_common" }, { "type": "object", @@ -524,6 +652,7 @@ "status": { "type": "string", "description": "The status of the peerconnection.", + "readOnly": true, "enum": [ "waiting-for-devices", "connected", @@ -702,36 +831,7 @@ "content": { "application/json": { "schema": { - "title": "Device Init", - "anyOf": [ - { - "allOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "type": "object", - "properties": { - "announcedAvailability": { - "type": "array", - "items": { - "$ref": "#/components/schemas/availability_rule" - } - } - } - } - ] - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device_init" }, "examples": { "microcontroller": { @@ -845,20 +945,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device" }, "examples": { "microcontroller": { @@ -1080,20 +1167,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device" }, "examples": { "microcontroller": { @@ -1245,36 +1319,7 @@ "content": { "application/json": { "schema": { - "title": "Device Init", - "anyOf": [ - { - "allOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "type": "object", - "properties": { - "announcedAvailability": { - "type": "array", - "items": { - "$ref": "#/components/schemas/availability_rule" - } - } - } - } - ] - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device_init" }, "examples": { "microcontroller": { @@ -1388,20 +1433,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device" }, "examples": { "microcontroller": { diff --git a/services/device/package-lock.json b/services/device/package-lock.json index 2198db63..ba85646f 100644 --- a/services/device/package-lock.json +++ b/services/device/package-lock.json @@ -29,6 +29,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.0.0", "@types/body-parser": "^1.19.2", "@types/express": "^4.17.13", + "@types/mocha": "^10.0.1", "@types/node": "^18.0.3", "@types/node-fetch": "^2.6.1", "@types/ws": "^8.5.3", @@ -1137,6 +1138,18 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/mocha": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", + "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "dev": true + }, "node_modules/@types/node": { "version": "18.13.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", diff --git a/services/device/package.json b/services/device/package.json index f4371f61..0917affd 100644 --- a/services/device/package.json +++ b/services/device/package.json @@ -29,6 +29,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.0.0", "@types/body-parser": "^1.19.2", "@types/express": "^4.17.13", + "@types/mocha": "^10.0.1", "@types/node": "^18.0.3", "@types/node-fetch": "^2.6.1", "@types/ws": "^8.5.3", diff --git a/services/device/src/config.ts b/services/device/src/config.ts index 352a5d0b..f2c666d1 100644 --- a/services/device/src/config.ts +++ b/services/device/src/config.ts @@ -33,7 +33,6 @@ export const config = { export const dataSourceConfig: DataSourceOptions = { type: 'sqlite', database: 'db/device.db', - synchronize: true, entities: [ DeviceOverviewModel, ConcreteDeviceModel, diff --git a/services/device/src/database/model.ts b/services/device/src/database/model.ts index d72c101a..0f240633 100644 --- a/services/device/src/database/model.ts +++ b/services/device/src/database/model.ts @@ -15,6 +15,12 @@ import { ManyToOne, } from 'typeorm' +export type DeviceModel = + | ConcreteDeviceModel + | DeviceGroupModel + | InstantiableBrowserDeviceModel + | InstantiableCloudDeviceModel + @Entity({ name: 'Device' }) @TableInheritance({ column: { diff --git a/services/device/src/database/repositories/device.ts b/services/device/src/database/repositories/device.ts index 3c8525a7..e2a5a22b 100644 --- a/services/device/src/database/repositories/device.ts +++ b/services/device/src/database/repositories/device.ts @@ -1,12 +1,12 @@ import { + Device, DeviceOverview, isConcreteDevice, isDeviceGroup, isInstantiableBrowserDevice, isInstantiableCloudDevice, } from '../../generated/types' -import { Device, DeviceModel } from '../../types/device' -import { DeviceOverviewModel } from '../model' +import { DeviceModel, DeviceOverviewModel } from '../model' import { concreteDeviceRepository } from './device/concreteDevice' import { deviceGroupRepository } from './device/deviceGroup' import { DeviceOverviewRepository } from './device/deviceOverview' diff --git a/services/device/src/database/repositories/device/deviceGroup.ts b/services/device/src/database/repositories/device/deviceGroup.ts index 1c16beed..d799f9dc 100644 --- a/services/device/src/database/repositories/device/deviceGroup.ts +++ b/services/device/src/database/repositories/device/deviceGroup.ts @@ -1,6 +1,5 @@ -import { DeviceGroup, DeviceReference } from '../../../generated/types' +import { Device, DeviceGroup, DeviceReference } from '../../../generated/types' import { apiClient } from '../../../globals' -import { Device } from '../../../types/device' import { DeviceGroupModel } from '../../model' import { DeviceOverviewRepository } from './deviceOverview' import { diff --git a/services/device/src/database/repositories/device/deviceOverview.ts b/services/device/src/database/repositories/device/deviceOverview.ts index 90ec597b..72ad4ee4 100644 --- a/services/device/src/database/repositories/device/deviceOverview.ts +++ b/services/device/src/database/repositories/device/deviceOverview.ts @@ -1,5 +1,5 @@ import { DeviceOverview } from '../../../generated/types' -import { deviceUrlFromId } from '../../../methods/utils' +import { deviceUrlFromId } from '../../../methods/urlFromId' import { DeviceOverviewModel } from '../../model' import { AbstractRepository } from '@crosslab/service-common' diff --git a/services/device/src/database/repositories/peerconnection.ts b/services/device/src/database/repositories/peerconnection.ts index aeb695ac..e1601569 100644 --- a/services/device/src/database/repositories/peerconnection.ts +++ b/services/device/src/database/repositories/peerconnection.ts @@ -1,5 +1,5 @@ import { Peerconnection } from '../../generated/types' -import { peerconnectionUrlFromId } from '../../methods/utils' +import { peerconnectionUrlFromId } from '../../methods/urlFromId' import { PeerconnectionModel } from '../model' import { AbstractApplicationDataSource, @@ -32,7 +32,6 @@ export class PeerconnectionRepository extends AbstractRepository< data: Peerconnection<'request'> ): Promise { if (data.type) model.type = data.type - if (data.status) model.status = data.status if (data.devices && data.devices.length !== 2) { throw new InvalidValueError( diff --git a/services/device/src/index.ts b/services/device/src/index.ts index 247ed879..da70a72c 100644 --- a/services/device/src/index.ts +++ b/services/device/src/index.ts @@ -2,8 +2,8 @@ import { config, dataSourceConfig } from './config' import { AppDataSource } from './database/dataSource' import { app } from './generated/index' -import { callbackHandling } from './methods/callbacks' -import { deviceHandling } from './operations/websocket' +import { callbackHandling } from './operations/callbacks' +import { websocketHandling } from './operations/devices' import { JWTVerify } from '@crosslab/service-common' import { IncomingMessage } from 'http' import { Socket } from 'net' @@ -49,7 +49,7 @@ AppDataSource.initialize(dataSourceConfig) const wsServer = new WebSocket.Server({ noServer: true }) app.wsListeners = new Map() app.ws = (path, listener) => app.wsListeners.set(path, listener) - deviceHandling(app) + websocketHandling(app) const server = app.listen(config.PORT) server.on( 'upgrade', diff --git a/services/device/src/methods/availability.ts b/services/device/src/methods/availability.ts index 8f693b3c..5c668bb6 100644 --- a/services/device/src/methods/availability.ts +++ b/services/device/src/methods/availability.ts @@ -1,105 +1,99 @@ import { AvailabilityRule, TimeSlot } from '../generated/types' +import { RemoveIndex } from '@crosslab/service-common' type TimeSlotModel = { start: number end: number } -type RemoveIndex = { - [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K] -} type AvailabilityRuleModel = Omit, 'start' | 'end'> & { start?: number end?: number } /** - * This function sorts a list of timeslots in ascending order of their start times. - * @param availability The list of timeslots to be sorted. - * @returns The sorted list of timeslots. - */ -function sortTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { - console.log('availability before sort:', JSON.stringify(availability, null, 4)) - availability.sort((a, b) => { - if (a.start < b.start) return -1 - if (a.start > b.start) return 1 - return 0 - }) - console.log('availability after sort:', JSON.stringify(availability, null, 4)) - return availability -} - -/** - * This function merges overlapping timeslots of a list of timeslots. - * @param availability The list of timeslots in which to merge overlapping timeslots. - * @returns The list of timeslots with no overlap. + * This function applies a list of availability rules to a list of timeslots. + * @param availability The list of timeslots to which to apply the availability rule. + * @param availabilityRules The list of availability rules to be applied. + * @param start The start time for the availability rules. + * @param end The end time for the availability rules. + * @returns The list of timeslots containing the changes of the applied availability rules. */ -function mergeOverlappingTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { - console.log('availability before merge:', JSON.stringify(availability, null, 4)) - for (let i = 0; i < availability.length; i++) { - if (i < availability.length - 1) { - if (availability[i + 1].start <= availability[i].end) { - availability = availability.splice(i + 1, 1) - i-- - } +export function applyAvailabilityRules( + availability: Required[], + availabilityRules: AvailabilityRule[], + start: number, + end: number +): Required[] { + let newAvailability = availability.map((timeSlot) => { + return { + start: Date.parse(timeSlot.start), + end: Date.parse(timeSlot.end), } + }) + for (const availabilityRule of availabilityRules) { + newAvailability = applyAvailabilityRule( + newAvailability, + { + ...availabilityRule, + start: Date.parse(availabilityRule.start ?? ''), + end: Date.parse(availabilityRule.end ?? ''), + }, + start, + end + ) } - console.log('availability after merge:', JSON.stringify(availability, null, 4)) - return availability + return newAvailability.map((timeSlotModel) => { + return { + start: new Date(timeSlotModel.start).toISOString(), + end: new Date(timeSlotModel.end).toISOString(), + } + }) } /** - * This function inverts a list of timeslots. - * @param availability The list of timeslots to invert. - * @param start The start time of the inverted list of timeslots. - * @param end The end time of the inverted list of timeslots. - * @returns The inverted list of timeslots. + * This function applies an availability rule to a list of timeslots. + * @param availability The list of timeslots to which to apply the availability rule. + * @param availabilityRule The availability rule to be applied. + * @param start The start time for the availability rule. + * @param end The end time for the availability rule. + * @returns The list of timeslots containing the changes of the applied availability rule. */ -function invertTimeSlots( +function applyAvailabilityRule( availability: TimeSlotModel[], + availabilityRule: AvailabilityRuleModel, start: number, end: number -): TimeSlotModel[] { - if (availability.length === 0) return [] - console.log('availability before invert:', JSON.stringify(availability, null, 4)) - - // sort by starttime - availability = sortTimeSlots(availability) +) { + if (availabilityRule.available === true || availabilityRule.available === undefined) { + console.log('applying availability rule for available = true') - // merge timeslots - availability = mergeOverlappingTimeSlots(availability) + // add all new timeslots + availability = addTimeSlotsFromRule(availability, availabilityRule, start, end) - const newAvailability: TimeSlotModel[] = [] + // sort by starttime + availability = sortTimeSlots(availability) - // create first timeslot - const firstTimeSlot: TimeSlotModel = { - start, - end: availability[0].start, - } + // merge timeslots + availability = mergeOverlappingTimeSlots(availability) + } else { + console.log('applying availability rule for available = false') - if (firstTimeSlot.start !== firstTimeSlot.end) newAvailability.push(firstTimeSlot) + // invert availability + availability = invertTimeSlots(availability, start, end) - // create intermediate timeslots - for (let i = 0; i < availability.length; i++) { - if (i < availability.length - 1) { - const timeSlot: TimeSlotModel = { - start: availability[i].end, - end: availability[i + 1].start, - } - newAvailability.push(timeSlot) - } - } + // add all new timeslots + availability = addTimeSlotsFromRule(availability, availabilityRule, start, end) - // create last timeslot - const lastTimeSlot: TimeSlotModel = { - start: availability[-1].end, - end, - } + // sort by starttime + availability = sortTimeSlots(availability) - if (lastTimeSlot.start !== lastTimeSlot.end) newAvailability.push(lastTimeSlot) + // merge timeslots + availability = mergeOverlappingTimeSlots(availability) - availability = newAvailability - console.log('availability after invert:', JSON.stringify(availability, null, 4)) + // invert availability + availability = invertTimeSlots(availability, start, end) + } return availability } @@ -198,87 +192,91 @@ function addTimeSlotsFromRule( } /** - * This function applies an availability rule to a list of timeslots. - * @param availability The list of timeslots to which to apply the availability rule. - * @param availabilityRule The availability rule to be applied. - * @param start The start time for the availability rule. - * @param end The end time for the availability rule. - * @returns The list of timeslots containing the changes of the applied availability rule. + * This function sorts a list of timeslots in ascending order of their start times. + * @param availability The list of timeslots to be sorted. + * @returns The sorted list of timeslots. */ -function applyAvailabilityRule( +function sortTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { + console.log('availability before sort:', JSON.stringify(availability, null, 4)) + availability.sort((a, b) => { + if (a.start < b.start) return -1 + if (a.start > b.start) return 1 + return 0 + }) + console.log('availability after sort:', JSON.stringify(availability, null, 4)) + return availability +} + +/** + * This function merges overlapping timeslots of a list of timeslots. + * @param availability The list of timeslots in which to merge overlapping timeslots. + * @returns The list of timeslots with no overlap. + */ +function mergeOverlappingTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { + console.log('availability before merge:', JSON.stringify(availability, null, 4)) + for (let i = 0; i < availability.length; i++) { + if (i < availability.length - 1) { + if (availability[i + 1].start <= availability[i].end) { + availability = availability.splice(i + 1, 1) + i-- + } + } + } + console.log('availability after merge:', JSON.stringify(availability, null, 4)) + return availability +} + +/** + * This function inverts a list of timeslots. + * @param availability The list of timeslots to invert. + * @param start The start time of the inverted list of timeslots. + * @param end The end time of the inverted list of timeslots. + * @returns The inverted list of timeslots. + */ +function invertTimeSlots( availability: TimeSlotModel[], - availabilityRule: AvailabilityRuleModel, start: number, end: number -) { - if (availabilityRule.available === true || availabilityRule.available === undefined) { - console.log('applying availability rule for available = true') - - // add all new timeslots - availability = addTimeSlotsFromRule(availability, availabilityRule, start, end) - - // sort by starttime - availability = sortTimeSlots(availability) +): TimeSlotModel[] { + if (availability.length === 0) return [] + console.log('availability before invert:', JSON.stringify(availability, null, 4)) - // merge timeslots - availability = mergeOverlappingTimeSlots(availability) - } else { - console.log('applying availability rule for available = false') + // sort by starttime + availability = sortTimeSlots(availability) - // invert availability - availability = invertTimeSlots(availability, start, end) + // merge timeslots + availability = mergeOverlappingTimeSlots(availability) - // add all new timeslots - availability = addTimeSlotsFromRule(availability, availabilityRule, start, end) + const newAvailability: TimeSlotModel[] = [] - // sort by starttime - availability = sortTimeSlots(availability) + // create first timeslot + const firstTimeSlot: TimeSlotModel = { + start, + end: availability[0].start, + } - // merge timeslots - availability = mergeOverlappingTimeSlots(availability) + if (firstTimeSlot.start !== firstTimeSlot.end) newAvailability.push(firstTimeSlot) - // invert availability - availability = invertTimeSlots(availability, start, end) + // create intermediate timeslots + for (let i = 0; i < availability.length; i++) { + if (i < availability.length - 1) { + const timeSlot: TimeSlotModel = { + start: availability[i].end, + end: availability[i + 1].start, + } + newAvailability.push(timeSlot) + } } - return availability -} -/** - * This function applies a list of availability rules to a list of timeslots. - * @param availability The list of timeslots to which to apply the availability rule. - * @param availabilityRules The list of availability rules to be applied. - * @param start The start time for the availability rules. - * @param end The end time for the availability rules. - * @returns The list of timeslots containing the changes of the applied availability rules. - */ -export function applyAvailabilityRules( - availability: Required[], - availabilityRules: AvailabilityRule[], - start: number, - end: number -): Required[] { - let newAvailability = availability.map((timeSlot) => { - return { - start: Date.parse(timeSlot.start), - end: Date.parse(timeSlot.end), - } - }) - for (const availabilityRule of availabilityRules) { - newAvailability = applyAvailabilityRule( - newAvailability, - { - ...availabilityRule, - start: Date.parse(availabilityRule.start ?? ''), - end: Date.parse(availabilityRule.end ?? ''), - }, - start, - end - ) + // create last timeslot + const lastTimeSlot: TimeSlotModel = { + start: availability[-1].end, + end, } - return newAvailability.map((timeSlotModel) => { - return { - start: new Date(timeSlotModel.start).toISOString(), - end: new Date(timeSlotModel.end).toISOString(), - } - }) + + if (lastTimeSlot.start !== lastTimeSlot.end) newAvailability.push(lastTimeSlot) + + availability = newAvailability + console.log('availability after invert:', JSON.stringify(availability, null, 4)) + return availability } diff --git a/services/device/src/methods/callbacks.ts b/services/device/src/methods/callbacks.ts index 17ac2f94..d2493160 100644 --- a/services/device/src/methods/callbacks.ts +++ b/services/device/src/methods/callbacks.ts @@ -1,19 +1,7 @@ import { config } from '../config' -import { AppDataSource } from '../database/dataSource' -import { PeerconnectionModel } from '../database/model' +import { DeviceModel, PeerconnectionModel } from '../database/model' import { deviceRepository } from '../database/repositories/device' import { peerconnectionRepository } from '../database/repositories/peerconnection' -import { - isConcreteDevice, - isDeviceGroup, - isInstantiableBrowserDevice, - isInstantiableCloudDevice, -} from '../generated/types' -import { apiClient, timeoutMap } from '../globals' -import { DeviceModel } from '../types/device' -import { signalingQueue } from './signaling' -import { InvalidValueError, MalformedBodyError } from '@crosslab/service-common' -import express from 'express' import fetch from 'node-fetch' export const callbackUrl: string = @@ -22,161 +10,6 @@ export const changedCallbacks = new Map>() export const closedCallbacks = new Map>() export const statusChangedCallbacks = new Map>() -/** - * This function adds the endpoint for incoming callbacks registered by the peerconnection service. - * @param app The express application the callback endpoint should be added to. - */ -export function callbackHandling(app: express.Application) { - // TODO: adapt callback handling after codegen update - app.post('/callbacks/device', async (req, res, next) => { - try { - const callback: any = req.body - if (typeof callback !== 'object') - throw new MalformedBodyError('Body of callback is not an object', 400) - const callbackType = getCallbackType(callback) - - switch (callbackType) { - case 'event': - return res.status(await handleEventCallback(callback)).send() - default: - throw new InvalidValueError( - `Callbacks of type "${req.body.callbackType}" are not supported`, - 400 - ) - } - } catch (error) { - return next(error) - } - }) -} - -/** - * This function attempts to get the type of an incoming callback. - * @param callback The incoming callback of which to get the type. - * @throws {MalformedBodyError} Thrown if the callback is malformed. - * @returns The type of the incoming callback. - */ -function getCallbackType(callback: any) { - if (typeof callback.callbackType !== 'string') { - throw new MalformedBodyError( - 'Property "callbackType" needs to be of type string', - 400 - ) - } - if (!callback.callbackType) { - throw new MalformedBodyError('Callbacks require property "callbackType"', 400) - } - return callback.callbackType as string -} - -/** - * This function handles an incoming event callback. - * @param callback The incoming event callback to be handled. - * @throws {MalformedBodyError} Thrown if the callback is malformed. - * @throws {InvalidValueError} Thrown if the type of the event callback is unknown. - * @returns The status code of the callback response. - */ -async function handleEventCallback(callback: any): Promise<200 | 410> { - if (!callback.eventType) { - throw new MalformedBodyError( - 'Callbacks of type "event" require property "eventType"', - 400 - ) - } - if (typeof callback.eventType !== 'string') { - throw new MalformedBodyError( - 'Property "callbackType" needs to be of type "string"', - 400 - ) - } - switch (callback.eventType) { - case 'device-changed': - return await handleDeviceChangedEventCallback(callback) - default: - throw new InvalidValueError( - `Event-callbacks of type "${callback.eventType}" are not supported`, - 400 - ) - } -} - -/** - * This function handles an incoming "device-changed" event callback. - * @param callback The incoming "device-changed" callback to be handled. - * @throws {MalformedBodyError} Thrown if the callback is malformed. - * @throws {InvalidValueError} Thrown if the device is not of type "device". - * @returns The status code for the response to the incoming callback. - */ -async function handleDeviceChangedEventCallback(callback: any): Promise<200 | 410> { - if (!callback.device) { - throw new MalformedBodyError( - 'Event-callbacks of type "device-changed" require property "device"', - 400 - ) - } - const device = callback.device - if ( - !isConcreteDevice(device) && - !isDeviceGroup(device) && - !isInstantiableBrowserDevice(device) && - !isInstantiableCloudDevice(device) - ) { - throw new MalformedBodyError('Property "device" is not a valid device', 400) - } - if (!device.url) { - throw new MalformedBodyError('Property "device" is missing url', 400) - } - if (!isConcreteDevice(device)) { - throw new InvalidValueError( - `Device needs to be of type "device" but is of type "${device.type}"`, - 400 // NOTE: error code - ) - } - const pendingConnectionsA = await AppDataSource.getRepository( - PeerconnectionModel - ).find({ - where: { - status: 'waiting-for-devices', - deviceA: { - url: device.url, - }, - }, - relations: { - deviceA: true, - deviceB: true, - }, - }) - const pendingConnectionsB = await AppDataSource.getRepository( - PeerconnectionModel - ).find({ - where: { - status: 'waiting-for-devices', - deviceB: { - url: device.url, - }, - }, - relations: { - deviceA: true, - deviceB: true, - }, - }) - const pendingConnections = [...pendingConnectionsA, ...pendingConnectionsB] - if (pendingConnections.length === 0) { - return 410 // TODO: check if 410 is the right choice here - } - for (const pendingConnection of pendingConnections) { - const deviceA = await apiClient.getDevice(pendingConnection.deviceA.url) - const deviceB = await apiClient.getDevice(pendingConnection.deviceB.url) - - if (deviceA.connected && deviceB.connected) { - clearTimeout(timeoutMap.get(pendingConnection.uuid)) - signalingQueue.addPeerconnection(pendingConnection) - timeoutMap.delete(pendingConnection.uuid) - } - } - return pendingConnections.length === 0 ? 410 : 200 -} - /** * This function sends a "device-changed" callback. * @param device The device for which to send the callback. diff --git a/services/device/src/methods/signaling.ts b/services/device/src/methods/signaling.ts index 0ce60550..c8ead030 100644 --- a/services/device/src/methods/signaling.ts +++ b/services/device/src/methods/signaling.ts @@ -3,7 +3,7 @@ import { PeerconnectionModel } from '../database/model' import { CreatePeerconnectionMessage } from '../generated/types' import { apiClient } from '../globals' import { sendStatusChangedCallback } from './callbacks' -import { peerconnectionUrlFromId } from './utils' +import { peerconnectionUrlFromId } from './urlFromId' import Queue from 'queue' class SignalingQueue { diff --git a/services/device/src/methods/utils.ts b/services/device/src/methods/urlFromId.ts similarity index 100% rename from services/device/src/methods/utils.ts rename to services/device/src/methods/urlFromId.ts diff --git a/services/device/src/operations/callbacks/event/deviceChanged.ts b/services/device/src/operations/callbacks/event/deviceChanged.ts new file mode 100644 index 00000000..b41ca993 --- /dev/null +++ b/services/device/src/operations/callbacks/event/deviceChanged.ts @@ -0,0 +1,85 @@ +import { peerconnectionRepository } from '../../../database/repositories/peerconnection' +import { + isConcreteDevice, + isDeviceGroup, + isInstantiableBrowserDevice, + isInstantiableCloudDevice, +} from '../../../generated/types' +import { apiClient, timeoutMap } from '../../../globals' +import { signalingQueue } from '../../../methods/signaling' +import { MalformedBodyError, InvalidValueError } from '@crosslab/service-common' + +/** + * This function handles an incoming "device-changed" event callback. + * @param callback The incoming "device-changed" callback to be handled. + * @throws {MalformedBodyError} Thrown if the callback is malformed. + * @throws {InvalidValueError} Thrown if the device is not of type "device". + * @returns The status code for the response to the incoming callback. + */ +export async function handleDeviceChangedEventCallback( + callback: any +): Promise<200 | 410> { + if (!callback.device) { + throw new MalformedBodyError( + 'Event-callbacks of type "device-changed" require property "device"', + 400 + ) + } + const device = callback.device + if ( + !isConcreteDevice(device) && + !isDeviceGroup(device) && + !isInstantiableBrowserDevice(device) && + !isInstantiableCloudDevice(device) + ) { + throw new MalformedBodyError('Property "device" is not a valid device', 400) + } + if (!device.url) { + throw new MalformedBodyError('Property "device" is missing url', 400) + } + if (!isConcreteDevice(device)) { + throw new InvalidValueError( + `Device needs to be of type "device" but is of type "${device.type}"`, + 400 // NOTE: error code + ) + } + const pendingConnectionsA = await peerconnectionRepository.find({ + where: { + status: 'waiting-for-devices', + deviceA: { + url: device.url, + }, + }, + relations: { + deviceA: true, + deviceB: true, + }, + }) + const pendingConnectionsB = await peerconnectionRepository.find({ + where: { + status: 'waiting-for-devices', + deviceB: { + url: device.url, + }, + }, + relations: { + deviceA: true, + deviceB: true, + }, + }) + const pendingConnections = [...pendingConnectionsA, ...pendingConnectionsB] + if (pendingConnections.length === 0) { + return 410 // TODO: check if 410 is the right choice here + } + for (const pendingConnection of pendingConnections) { + const deviceA = await apiClient.getDevice(pendingConnection.deviceA.url) + const deviceB = await apiClient.getDevice(pendingConnection.deviceB.url) + + if (deviceA.connected && deviceB.connected) { + clearTimeout(timeoutMap.get(pendingConnection.uuid)) + signalingQueue.addPeerconnection(pendingConnection) + timeoutMap.delete(pendingConnection.uuid) + } + } + return pendingConnections.length === 0 ? 410 : 200 +} diff --git a/services/device/src/operations/callbacks/event/index.ts b/services/device/src/operations/callbacks/event/index.ts new file mode 100644 index 00000000..9368aecd --- /dev/null +++ b/services/device/src/operations/callbacks/event/index.ts @@ -0,0 +1,33 @@ +import { handleDeviceChangedEventCallback } from './deviceChanged' +import { MalformedBodyError, InvalidValueError } from '@crosslab/service-common' + +/** + * This function handles an incoming event callback. + * @param callback The incoming event callback to be handled. + * @throws {MalformedBodyError} Thrown if the callback is malformed. + * @throws {InvalidValueError} Thrown if the type of the event callback is unknown. + * @returns The status code of the callback response. + */ +export async function handleEventCallback(callback: any): Promise<200 | 410> { + if (!callback.eventType) { + throw new MalformedBodyError( + 'Callbacks of type "event" require property "eventType"', + 400 + ) + } + if (typeof callback.eventType !== 'string') { + throw new MalformedBodyError( + 'Property "callbackType" needs to be of type "string"', + 400 + ) + } + switch (callback.eventType) { + case 'device-changed': + return await handleDeviceChangedEventCallback(callback) + default: + throw new InvalidValueError( + `Event-callbacks of type "${callback.eventType}" are not supported`, + 400 + ) + } +} diff --git a/services/device/src/operations/callbacks/index.ts b/services/device/src/operations/callbacks/index.ts new file mode 100644 index 00000000..5dcd8a21 --- /dev/null +++ b/services/device/src/operations/callbacks/index.ts @@ -0,0 +1,51 @@ +import { handleEventCallback } from './event' +import { MalformedBodyError, InvalidValueError } from '@crosslab/service-common' +import express from 'express' + +export * from '../../methods/callbacks' + +/** + * This function adds the endpoint for incoming callbacks registered by the peerconnection service. + * @param app The express application the callback endpoint should be added to. + */ +export function callbackHandling(app: express.Application) { + app.post('/callbacks/device', async (req, res, next) => { + try { + const callback: any = req.body + if (typeof callback !== 'object') + throw new MalformedBodyError('Body of callback is not an object', 400) + const callbackType = getCallbackType(callback) + + switch (callbackType) { + case 'event': + return res.status(await handleEventCallback(callback)).send() + default: + throw new InvalidValueError( + `Callbacks of type "${req.body.callbackType}" are not supported`, + 400 + ) + } + } catch (error) { + return next(error) + } + }) +} + +/** + * This function attempts to get the type of an incoming callback. + * @param callback The incoming callback of which to get the type. + * @throws {MalformedBodyError} Thrown if the callback is malformed. + * @returns The type of the incoming callback. + */ +function getCallbackType(callback: any) { + if (typeof callback.callbackType !== 'string') { + throw new MalformedBodyError( + 'Property "callbackType" needs to be of type string', + 400 + ) + } + if (!callback.callbackType) { + throw new MalformedBodyError('Callbacks require property "callbackType"', 400) + } + return callback.callbackType as string +} diff --git a/services/device/src/operations/devices/device/patch.ts b/services/device/src/operations/devices/device/patch.ts index c15d535e..0f8e1430 100644 --- a/services/device/src/operations/devices/device/patch.ts +++ b/services/device/src/operations/devices/device/patch.ts @@ -1,7 +1,7 @@ -import { MissingPropertyError } from "@crosslab/service-common" -import { deviceRepository } from "../../../database/repositories/device" -import { patchDevicesByDeviceIdSignature } from "../../../generated/signatures" -import { changedCallbacks, sendChangedCallback } from "../../../methods/callbacks" +import { deviceRepository } from '../../../database/repositories/device' +import { patchDevicesByDeviceIdSignature } from '../../../generated/signatures' +import { changedCallbacks, sendChangedCallback } from '../../../methods/callbacks' +import { MissingPropertyError } from '@crosslab/service-common' /** * This function implements the functionality for handling PATCH requests on /devices/{device_id} endpoint. @@ -56,4 +56,4 @@ export const patchDevicesByDeviceId: patchDevicesByDeviceIdSignature = async ( status: 200, body: await deviceRepository.format(device), } -} \ No newline at end of file +} diff --git a/services/device/src/operations/devices/device/post.ts b/services/device/src/operations/devices/device/post.ts index 9f480885..428d1237 100644 --- a/services/device/src/operations/devices/device/post.ts +++ b/services/device/src/operations/devices/device/post.ts @@ -1,10 +1,14 @@ -import { ForbiddenOperationError, InvalidValueError, MissingPropertyError } from "@crosslab/service-common" -import { deviceRepository } from "../../../database/repositories/device" -import { postDevicesByDeviceIdSignature } from "../../../generated/signatures" -import { ConcreteDevice } from "../../../generated/types" -import { apiClient } from "../../../globals" -import { changedCallbacks } from "../../../methods/callbacks" -import { deviceUrlFromId } from "../../../methods/utils" +import { deviceRepository } from '../../../database/repositories/device' +import { postDevicesByDeviceIdSignature } from '../../../generated/signatures' +import { ConcreteDevice } from '../../../generated/types' +import { apiClient } from '../../../globals' +import { changedCallbacks } from '../../../methods/callbacks' +import { deviceUrlFromId } from '../../../methods/urlFromId' +import { + ForbiddenOperationError, + InvalidValueError, + MissingPropertyError, +} from '@crosslab/service-common' /** * This function implements the functionality for handling POST requests on /devices/{device_id} endpoint. @@ -86,4 +90,4 @@ export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( instance: instance, }, } -} \ No newline at end of file +} diff --git a/services/device/src/operations/devices/device/signaling/post.ts b/services/device/src/operations/devices/device/signaling/post.ts index 519c47c0..4e51485f 100644 --- a/services/device/src/operations/devices/device/signaling/post.ts +++ b/services/device/src/operations/devices/device/signaling/post.ts @@ -1,9 +1,14 @@ -import { ForbiddenOperationError, MissingPropertyError, UnrelatedPeerconnectionError, MissingEntityError } from "@crosslab/service-common" -import { deviceRepository } from "../../../../database/repositories/device" -import { postDevicesByDeviceIdSignalingSignature } from "../../../../generated/signatures" -import { apiClient } from "../../../../globals" -import { deviceUrlFromId } from "../../../../methods/utils" -import { connectedDevices } from "../../../websocket" +import { connectedDevices } from '../..' +import { deviceRepository } from '../../../../database/repositories/device' +import { postDevicesByDeviceIdSignalingSignature } from '../../../../generated/signatures' +import { apiClient } from '../../../../globals' +import { deviceUrlFromId } from '../../../../methods/urlFromId' +import { + ForbiddenOperationError, + MissingPropertyError, + UnrelatedPeerconnectionError, + MissingEntityError, +} from '@crosslab/service-common' /** * This function implements the functionality for handling POST requests on /devices/{device_id}/signaling endpoint. @@ -66,4 +71,4 @@ export const postDevicesByDeviceIdSignaling: postDevicesByDeviceIdSignalingSigna return { status: 200, } - } \ No newline at end of file + } diff --git a/services/device/src/operations/devices/index.ts b/services/device/src/operations/devices/index.ts index 0ce71aa1..2ca01cc8 100644 --- a/services/device/src/operations/devices/index.ts +++ b/services/device/src/operations/devices/index.ts @@ -1,3 +1,4 @@ export * from './device' export * from './get' export * from './post' +export * from './websocket' diff --git a/services/device/src/operations/devices/post.ts b/services/device/src/operations/devices/post.ts index 3c8d551b..f0170fbf 100644 --- a/services/device/src/operations/devices/post.ts +++ b/services/device/src/operations/devices/post.ts @@ -1,6 +1,6 @@ -import { deviceRepository } from "../../database/repositories/device" -import { postDevicesSignature } from "../../generated/signatures" -import { changedCallbacks } from "../../methods/callbacks" +import { deviceRepository } from '../../database/repositories/device' +import { postDevicesSignature } from '../../generated/signatures' +import { changedCallbacks } from '../../methods/callbacks' /** * This function implements the functionality for handling POST requests on /devices endpoint. @@ -30,4 +30,4 @@ export const postDevices: postDevicesSignature = async (parameters, body, user) status: 201, body: await deviceRepository.format(device), } -} \ No newline at end of file +} diff --git a/services/device/src/operations/websocket.ts b/services/device/src/operations/devices/websocket/index.ts similarity index 91% rename from services/device/src/operations/websocket.ts rename to services/device/src/operations/devices/websocket/index.ts index 72586491..9634e842 100644 --- a/services/device/src/operations/websocket.ts +++ b/services/device/src/operations/devices/websocket/index.ts @@ -1,12 +1,12 @@ -import { AppDataSource } from '../database/dataSource' -import { ConcreteDeviceModel } from '../database/model' +import { AppDataSource } from '../../../database/dataSource' +import { ConcreteDeviceModel } from '../../../database/model' import { isMessage, isAuthenticationMessage, AuthenticationMessage, -} from '../generated/types' -import { sendChangedCallback } from '../methods/callbacks' -import { handleDeviceMessage } from '../methods/messageHandling' +} from '../../../generated/types' +import { sendChangedCallback } from '../../../methods/callbacks' +import { handleDeviceMessage } from './messageHandling' import WebSocket from 'ws' export const connectedDevices = new Map() @@ -15,7 +15,7 @@ export const connectedDevices = new Map() * This function adds the /devices/ws endpoint, including its functionality, to an express application. * @param app The express application to add the /devices/ws endpoint to. */ -export function deviceHandling(app: Express.Application) { +export function websocketHandling(app: Express.Application) { // TODO: close Peerconnections that have device as participant when websocket connection is closed? app.ws('/devices/websocket', (ws) => { // authenticate and start heartbeat diff --git a/services/device/src/methods/messageHandling.ts b/services/device/src/operations/devices/websocket/messageHandling.ts similarity index 90% rename from services/device/src/methods/messageHandling.ts rename to services/device/src/operations/devices/websocket/messageHandling.ts index f0cd6cf2..ab0c640c 100644 --- a/services/device/src/methods/messageHandling.ts +++ b/services/device/src/operations/devices/websocket/messageHandling.ts @@ -1,7 +1,7 @@ -import { ConcreteDeviceModel } from '../database/model' -import { SignalingMessage, Message, isSignalingMessage } from '../generated/types' -import { apiClient } from '../globals' -import { deviceUrlFromId } from './utils' +import { ConcreteDeviceModel } from '../../../database/model' +import { SignalingMessage, Message, isSignalingMessage } from '../../../generated/types' +import { apiClient } from '../../../globals' +import { deviceUrlFromId } from '../../../methods/urlFromId' import { MissingPropertyError, UnrelatedPeerconnectionError, diff --git a/services/device/src/operations/index.ts b/services/device/src/operations/index.ts index 096afd77..a7c651a5 100644 --- a/services/device/src/operations/index.ts +++ b/services/device/src/operations/index.ts @@ -1,7 +1,9 @@ +import * as callbacks from './callbacks' import * as operationsDevices from './devices' import * as operationsPeerconnections from './peerconnections' export default { ...operationsDevices, ...operationsPeerconnections, + ...callbacks, } diff --git a/services/device/src/operations/peerconnections/peerconnection/delete.ts b/services/device/src/operations/peerconnections/peerconnection/delete.ts index d30d3efd..81f316c4 100644 --- a/services/device/src/operations/peerconnections/peerconnection/delete.ts +++ b/services/device/src/operations/peerconnections/peerconnection/delete.ts @@ -3,7 +3,7 @@ import { deletePeerconnectionsByPeerconnectionIdSignature } from '../../../gener import { ClosePeerconnectionMessage } from '../../../generated/types' import { apiClient } from '../../../globals' import { sendClosedCallback } from '../../../methods/callbacks' -import { peerconnectionUrlFromId } from '../../../methods/utils' +import { peerconnectionUrlFromId } from '../../../methods/urlFromId' /** * This function implements the functionality for handling DELETE requests on /peerconnection/{peerconnection_id} endpoint. diff --git a/services/device/src/types/device.ts b/services/device/src/types/device.ts deleted file mode 100644 index f33fe715..00000000 --- a/services/device/src/types/device.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - ConcreteDeviceModel, - DeviceGroupModel, - InstantiableBrowserDeviceModel, - InstantiableCloudDeviceModel, -} from '../database/model' -import { - ConcreteDevice, - DeviceGroup, - InstantiableBrowserDevice, - InstantiableCloudDevice, -} from '../generated/types' - -export type Device = - | ConcreteDevice - | DeviceGroup - | InstantiableBrowserDevice - | InstantiableCloudDevice - -export type DeviceModel = - | ConcreteDeviceModel - | DeviceGroupModel - | InstantiableBrowserDeviceModel - | InstantiableCloudDeviceModel diff --git a/services/device/test/config.spec.ts b/services/device/test/config.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/data/device.spec.ts b/services/device/test/data/device.spec.ts new file mode 100644 index 00000000..1b5ca6b6 --- /dev/null +++ b/services/device/test/data/device.spec.ts @@ -0,0 +1,32 @@ +import { DeviceRepository } from '../../src/database/repositories/device' +import { EntityData } from '@crosslab/service-common' + +export const deviceNames = ['concrete device example'] as const +export type DeviceName = (typeof deviceNames)[number] +export type DeviceData = Record> + +export const deviceData: DeviceData = { + 'concrete device example': { + request: { + type: 'device', + name: 'Concrete Device Example', + description: 'An example for a concrete device.', + }, + model: { + uuid: '32348c89-f302-408f-8582-cb9783c74fbb', + type: 'device', + name: 'Concrete Device Example', + description: 'An example for a concrete device.', + owner: 'http://localhost/users/superadmin', + }, + response: { + url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', + type: 'device', + name: 'Concrete Device Example', + description: 'An example for a concrete device.', + owner: 'http://localhost/users/superadmin', + connected: false, + announcedAvailability: [], + }, + }, +} diff --git a/services/device/test/data/index.spec.ts b/services/device/test/data/index.spec.ts new file mode 100644 index 00000000..865c7177 --- /dev/null +++ b/services/device/test/data/index.spec.ts @@ -0,0 +1,19 @@ +import { DeviceRepository } from '../../src/database/repositories/device' +import { PeerconnectionRepository } from '../../src/database/repositories/peerconnection' +import { deviceData, DeviceName } from './device.spec' +import { peerconnectionData, PeerconnectionName } from './peerconnection.spec' +import { GenericTestData } from '@crosslab/service-common' + +export type TestData = GenericTestData< + [ + ['devices', DeviceName, DeviceRepository], + ['peerconnections', PeerconnectionName, PeerconnectionRepository] + ] +> + +export function prepareTestData(): TestData { + return { + devices: deviceData, + peerconnections: peerconnectionData, + } +} diff --git a/services/device/test/data/peerconnection.spec.ts b/services/device/test/data/peerconnection.spec.ts new file mode 100644 index 00000000..f8f24261 --- /dev/null +++ b/services/device/test/data/peerconnection.spec.ts @@ -0,0 +1,41 @@ +import { PeerconnectionRepository } from '../../src/database/repositories/peerconnection' +import { EntityData } from '@crosslab/service-common' + +export const peerconnectionNames = ['example peerconnection'] as const +export type PeerconnectionName = (typeof peerconnectionNames)[number] +export type PeerconnectionData = Record< + PeerconnectionName, + EntityData +> + +export const peerconnectionData: PeerconnectionData = { + 'example peerconnection': { + request: { + type: 'webrtc', + devices: [ + { url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb' }, + { url: 'http://localhost/devices/aa3272e6-6f4e-4d5b-a4a9-252d9bac9bd3' }, + ], + }, + model: { + uuid: '184f5ada-84fe-4d33-ab7d-22801be1a4ff', + type: 'webrtc', + status: 'waiting-for-devices', + deviceA: { + url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', + }, + deviceB: { + url: 'http://localhost/devices/aa3272e6-6f4e-4d5b-a4a9-252d9bac9bd3', + }, + }, + response: { + url: 'http://localhost/peeerconnections/184f5ada-84fe-4d33-ab7d-22801be1a4ff', + type: 'webrtc', + status: 'waiting-for-devices', + devices: [ + { url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb' }, + { url: 'http://localhost/devices/aa3272e6-6f4e-4d5b-a4a9-252d9bac9bd3' }, + ], + }, + }, +} diff --git a/services/device/test/database/dataSource.spec.ts b/services/device/test/database/dataSource.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/database/index.spec.ts b/services/device/test/database/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/database/model.spec.ts b/services/device/test/database/model.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/database/repositories/device.spec.ts b/services/device/test/database/repositories/device.spec.ts new file mode 100644 index 00000000..cef051fc --- /dev/null +++ b/services/device/test/database/repositories/device.spec.ts @@ -0,0 +1,90 @@ +import { AppDataSource } from '../../../src/database/dataSource' +import { DeviceModel } from '../../../src/database/model' +import { + deviceRepository, + DeviceRepository, +} from '../../../src/database/repositories/device' +import { Device, DeviceInit } from '../../../src/generated/types' +import { DeviceName } from '../../data/device.spec' +import { initTestDatabase } from './index.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import { FindOptionsWhere } from 'typeorm' + +class DeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< + DeviceName, + DeviceRepository +> { + protected name = 'devices' as const + protected repository = deviceRepository + protected getEntityData = async () => (await initTestDatabase()).devices + protected RepositoryClass = DeviceRepository + + constructor() { + super(AppDataSource) + } + + validateCreate( + model: DeviceModel, + data?: DeviceInit<'request'> | undefined + ): boolean { + if (!data) { + return true + } + + if (data?.name) assert(model.name === data.name) + if (data?.description) assert(model.description === data.description) + + switch (model.type) { + case 'cloud instantiable': + assert(model.type === data.type) + if (data.instantiateUrl) + assert(model.instantiateUrl === data.instantiateUrl) + if (data.services) assert(model.services === data.services) + break + case 'device': + assert(model.type === data.type) + if (data.services) assert(model.services === data.services) + break + case 'edge instantiable': + assert(model.type === data.type) + if (data.codeUrl) assert(model.codeUrl === data.codeUrl) + if (data.services) assert(model.services === data.services) + break + case 'group': + assert(model.type === data.type) + if (data.devices) { + for (const device of data.devices) { + assert(model.devices?.find((d) => d.url === device.url)) + } + for (const device of model.devices ?? []) { + assert(data.devices.find((d) => d.url === device.url)) + } + } + break + } + + return true + } + validateWrite(model: DeviceModel, data: Device<'request'>): boolean { + throw new Error('Method not implemented.') + } + validateFormat(model: DeviceModel, data: Device<'response'>): boolean { + throw new Error('Method not implemented.') + } + compareModels( + firstModel: DeviceModel, + secondModel: DeviceModel, + complete?: boolean | undefined + ): boolean { + throw new Error('Method not implemented.') + } + compareFormatted(first: Device<'response'>, second: Device<'response'>): boolean { + throw new Error('Method not implemented.') + } + getFindOptionsWhere(model?: DeviceModel | undefined): FindOptionsWhere { + throw new Error('Method not implemented.') + } +} + +export const deviceRepositoryTestSuite = new DeviceRepositoryTestSuite() diff --git a/services/device/test/database/repositories/index.spec.ts b/services/device/test/database/repositories/index.spec.ts new file mode 100644 index 00000000..7c26bb01 --- /dev/null +++ b/services/device/test/database/repositories/index.spec.ts @@ -0,0 +1,70 @@ +import { AppDataSource } from '../../../src/database/dataSource' +import { + DeviceOverviewModel, + ConcreteDeviceModel, + InstantiableDeviceOverviewModel, + InstantiableCloudDeviceModel, + InstantiableBrowserDeviceModel, + DeviceGroupModel, + PeerconnectionModel, +} from '../../../src/database/model' +import { deviceRepository } from '../../../src/database/repositories/device' +import { peerconnectionRepository } from '../../../src/database/repositories/peerconnection' +import { deviceNames } from '../../data/device.spec' +import { prepareTestData, TestData } from '../../data/index.spec' +import { peerconnectionNames } from '../../data/peerconnection.spec' +import { deviceRepositoryTestSuite } from './device.spec' +import { peerconnectionRepositoryTestSuite } from './peerconnection.spec' +import { DataSourceOptions } from 'typeorm' + +const repositoryTestSuites = [ + deviceRepositoryTestSuite, + peerconnectionRepositoryTestSuite, +] + +export default () => + describe('Repositories', function () { + let suite: Mocha.Suite = this + + it('should setup the repository tests', async function () { + this.timeout(0) + + for (const repositoryTestSuite of repositoryTestSuites) { + await repositoryTestSuite.initialize() + suite.addSuite(repositoryTestSuite.execute()) + } + }) + }) + +export async function initTestDatabase(): Promise { + const dataSourceConfig: DataSourceOptions = { + type: 'sqlite', + database: ':memory:', + synchronize: true, + dropSchema: true, + entities: [ + DeviceOverviewModel, + ConcreteDeviceModel, + InstantiableDeviceOverviewModel, + InstantiableCloudDeviceModel, + InstantiableBrowserDeviceModel, + DeviceGroupModel, + PeerconnectionModel, + ], + } + + const testData = prepareTestData() + await AppDataSource.initialize(dataSourceConfig) + + for (const deviceName of deviceNames) { + await deviceRepository.save(testData.devices[deviceName].model) + } + + for (const peerconnectionName of peerconnectionNames) { + await peerconnectionRepository.save( + testData.peerconnections[peerconnectionName].model + ) + } + + return testData +} diff --git a/services/device/test/database/repositories/peerconnection.spec.ts b/services/device/test/database/repositories/peerconnection.spec.ts new file mode 100644 index 00000000..9f3c0b1a --- /dev/null +++ b/services/device/test/database/repositories/peerconnection.spec.ts @@ -0,0 +1,66 @@ +import { AppDataSource } from '../../../src/database/dataSource' +import { PeerconnectionModel } from '../../../src/database/model' +import { + peerconnectionRepository, + PeerconnectionRepository, +} from '../../../src/database/repositories/peerconnection' +import { Peerconnection } from '../../../src/generated/types' +import { PeerconnectionName } from '../../data/peerconnection.spec' +import { initTestDatabase } from './index.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import { FindOptionsWhere } from 'typeorm' + +class PeerconnectionRepositoryTestSuite extends AbstractRepositoryTestSuite< + PeerconnectionName, + PeerconnectionRepository +> { + protected name = 'peerconnections' as const + protected repository = peerconnectionRepository + protected getEntityData = async () => (await initTestDatabase()).peerconnections + protected RepositoryClass = PeerconnectionRepository + + constructor() { + super(AppDataSource) + } + + validateCreate( + model: PeerconnectionModel, + data?: Peerconnection<'request'> + ): boolean { + throw new Error('Method not implemented.') + } + + validateWrite(model: PeerconnectionModel, data: Peerconnection<'request'>): boolean { + throw new Error('Method not implemented.') + } + + validateFormat( + model: PeerconnectionModel, + data: Peerconnection<'response'> + ): boolean { + throw new Error('Method not implemented.') + } + + compareModels( + firstModel: PeerconnectionModel, + secondModel: PeerconnectionModel, + complete?: boolean + ): boolean { + throw new Error('Method not implemented.') + } + + compareFormatted( + first: Peerconnection<'response'>, + second: Peerconnection<'response'> + ): boolean { + throw new Error('Method not implemented.') + } + + getFindOptionsWhere( + model?: PeerconnectionModel + ): FindOptionsWhere { + throw new Error('Method not implemented.') + } +} + +export const peerconnectionRepositoryTestSuite = new PeerconnectionRepositoryTestSuite() diff --git a/services/device/test/index.spec.ts b/services/device/test/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/methods/availability.spec.ts b/services/device/test/methods/availability.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/methods/callbacks.spec.ts b/services/device/test/methods/callbacks.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/methods/index.spec.ts b/services/device/test/methods/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/methods/signaling.spec.ts b/services/device/test/methods/signaling.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/methods/urlFromId.spec.ts b/services/device/test/methods/urlFromId.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/callbacks/event/deviceChanged.spec.ts b/services/device/test/operations/callbacks/event/deviceChanged.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/callbacks/event/index.spec.ts b/services/device/test/operations/callbacks/event/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/callbacks/index.spec.ts b/services/device/test/operations/callbacks/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/availability/index.spec.ts b/services/device/test/operations/devices/device/availability/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/availability/post.spec.ts b/services/device/test/operations/devices/device/availability/post.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/delete.spec.ts b/services/device/test/operations/devices/device/delete.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/get.spec.ts b/services/device/test/operations/devices/device/get.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/index.spec.ts b/services/device/test/operations/devices/device/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/patch.spec.ts b/services/device/test/operations/devices/device/patch.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/post.spec.ts b/services/device/test/operations/devices/device/post.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/signaling/index.spec.ts b/services/device/test/operations/devices/device/signaling/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/signaling/post.spec.ts b/services/device/test/operations/devices/device/signaling/post.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/websocket/index.spec.ts b/services/device/test/operations/devices/device/websocket/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/device/websocket/post.spec.ts b/services/device/test/operations/devices/device/websocket/post.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/get.spec.ts b/services/device/test/operations/devices/get.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/index.spec.ts b/services/device/test/operations/devices/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/post.spec.ts b/services/device/test/operations/devices/post.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/websocket/index.spec.ts b/services/device/test/operations/devices/websocket/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/devices/websocket/messageHandling.spec.ts b/services/device/test/operations/devices/websocket/messageHandling.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/index.spec.ts b/services/device/test/operations/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/peerconnections/get.spec.ts b/services/device/test/operations/peerconnections/get.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/peerconnections/index.spec.ts b/services/device/test/operations/peerconnections/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts b/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/peerconnections/peerconnection/get.spec.ts b/services/device/test/operations/peerconnections/peerconnection/get.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/peerconnections/peerconnection/index.spec.ts b/services/device/test/operations/peerconnections/peerconnection/index.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/test/operations/peerconnections/post.spec.ts b/services/device/test/operations/peerconnections/post.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/services/device/tsconfig.json b/services/device/tsconfig.json deleted file mode 120000 index 3c02b682..00000000 --- a/services/device/tsconfig.json +++ /dev/null @@ -1 +0,0 @@ -../../common/node/tsconfig-app.json \ No newline at end of file diff --git a/services/device/tsconfig.json b/services/device/tsconfig.json new file mode 100644 index 00000000..04e181b2 --- /dev/null +++ b/services/device/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true, + "target": "ES2021", + "lib": ["ES2021"], + "esModuleInterop": true, + "outDir": "app", + "strict": true, + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "skipLibCheck": true + }, + "include": ["src","test"] + } + \ No newline at end of file From ad726de178911506fa57f51dbdfa58e29eca1bbc Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 21 Mar 2023 09:59:59 +0100 Subject: [PATCH 06/33] Small changes and fixes - Change structure of test data folder - Fix small issue in auth service (test suite name) --- .../repositories/activeKeyRepository.spec.ts | 4 +- services/device/api/content/device_body.yml | 2 +- services/device/api/content/device_init.yml | 7 ++++ services/device/api/resources/devices.yml | 2 +- services/device/dist/openapi.json | 2 +- services/device/test/data/device.spec.ts | 32 --------------- .../test/data/devices/concrete_device.spec.ts | 34 +++++++++++++++ .../device/test/data/devices/index.spec.ts | 11 +++++ services/device/test/data/index.spec.ts | 4 +- .../device/test/data/peerconnection.spec.ts | 41 ------------------- .../example_peerconnection.spec.ts | 31 ++++++++++++++ .../test/data/peerconnections/index.spec.ts | 14 +++++++ .../test/database/repositories/index.spec.ts | 2 +- .../repositories/peerconnection.spec.ts | 2 +- 14 files changed, 106 insertions(+), 82 deletions(-) create mode 100644 services/device/api/content/device_init.yml delete mode 100644 services/device/test/data/device.spec.ts create mode 100644 services/device/test/data/devices/concrete_device.spec.ts create mode 100644 services/device/test/data/devices/index.spec.ts delete mode 100644 services/device/test/data/peerconnection.spec.ts create mode 100644 services/device/test/data/peerconnections/example_peerconnection.spec.ts create mode 100644 services/device/test/data/peerconnections/index.spec.ts diff --git a/services/auth/test/database/repositories/activeKeyRepository.spec.ts b/services/auth/test/database/repositories/activeKeyRepository.spec.ts index f1976d83..d41de912 100644 --- a/services/auth/test/database/repositories/activeKeyRepository.spec.ts +++ b/services/auth/test/database/repositories/activeKeyRepository.spec.ts @@ -11,7 +11,7 @@ import { AbstractRepositoryTestSuite } from '@crosslab/service-common' import assert from 'assert' import { FindOptionsWhere } from 'typeorm' -class ActiveKeyRepositoryTest extends AbstractRepositoryTestSuite< +class ActiveKeyRepositoryTestSuite extends AbstractRepositoryTestSuite< ActiveKeyName, ActiveKeyRepository > { @@ -72,4 +72,4 @@ class ActiveKeyRepositoryTest extends AbstractRepositoryTestSuite< } } -export const activeKeyRepositoryTestSuite = new ActiveKeyRepositoryTest() +export const activeKeyRepositoryTestSuite = new ActiveKeyRepositoryTestSuite() diff --git a/services/device/api/content/device_body.yml b/services/device/api/content/device_body.yml index 3289f4cd..1fb04f58 100644 --- a/services/device/api/content/device_body.yml +++ b/services/device/api/content/device_body.yml @@ -1,6 +1,6 @@ # yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json schema: - $ref: ../schemas/devices/device_init.yml + $ref: ../schemas/devices/device.yml examples: microcontroller: value: diff --git a/services/device/api/content/device_init.yml b/services/device/api/content/device_init.yml new file mode 100644 index 00000000..3289f4cd --- /dev/null +++ b/services/device/api/content/device_init.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json +schema: + $ref: ../schemas/devices/device_init.yml +examples: + microcontroller: + value: + $ref: '../examples/device_microcontroller.yml' \ No newline at end of file diff --git a/services/device/api/resources/devices.yml b/services/device/api/resources/devices.yml index 27ebe401..fc6075a1 100644 --- a/services/device/api/resources/devices.yml +++ b/services/device/api/resources/devices.yml @@ -41,7 +41,7 @@ post: required: true content: application/json: - $ref: "../content/device_body.yml" + $ref: "../content/device_init.yml" responses: 201: description: The device was created. A JSON representation of the new device is returned. diff --git a/services/device/dist/openapi.json b/services/device/dist/openapi.json index 317b53cc..4f9a657a 100644 --- a/services/device/dist/openapi.json +++ b/services/device/dist/openapi.json @@ -1319,7 +1319,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/device_init" + "$ref": "#/components/schemas/device" }, "examples": { "microcontroller": { diff --git a/services/device/test/data/device.spec.ts b/services/device/test/data/device.spec.ts deleted file mode 100644 index 1b5ca6b6..00000000 --- a/services/device/test/data/device.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { DeviceRepository } from '../../src/database/repositories/device' -import { EntityData } from '@crosslab/service-common' - -export const deviceNames = ['concrete device example'] as const -export type DeviceName = (typeof deviceNames)[number] -export type DeviceData = Record> - -export const deviceData: DeviceData = { - 'concrete device example': { - request: { - type: 'device', - name: 'Concrete Device Example', - description: 'An example for a concrete device.', - }, - model: { - uuid: '32348c89-f302-408f-8582-cb9783c74fbb', - type: 'device', - name: 'Concrete Device Example', - description: 'An example for a concrete device.', - owner: 'http://localhost/users/superadmin', - }, - response: { - url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', - type: 'device', - name: 'Concrete Device Example', - description: 'An example for a concrete device.', - owner: 'http://localhost/users/superadmin', - connected: false, - announcedAvailability: [], - }, - }, -} diff --git a/services/device/test/data/devices/concrete_device.spec.ts b/services/device/test/data/devices/concrete_device.spec.ts new file mode 100644 index 00000000..f4c3b407 --- /dev/null +++ b/services/device/test/data/devices/concrete_device.spec.ts @@ -0,0 +1,34 @@ +import { DeviceRepository } from '../../../src/database/repositories/device' +import { EntityData } from '@crosslab/service-common' + +const uuid = '32348c89-f302-408f-8582-cb9783c74fbb' +const type = 'device' +const name = 'Concrete Device Example' +const description = 'An example for a concrete device' +const owner = 'http://localhost/users/superadmin' + +const concrete_device: EntityData = { + request: { + type, + name, + description, + }, + model: { + uuid, + type, + name, + description, + owner, + }, + response: { + url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', + type, + name, + description, + owner, + connected: false, + announcedAvailability: [], + }, +} + +export default concrete_device diff --git a/services/device/test/data/devices/index.spec.ts b/services/device/test/data/devices/index.spec.ts new file mode 100644 index 00000000..a156cc76 --- /dev/null +++ b/services/device/test/data/devices/index.spec.ts @@ -0,0 +1,11 @@ +import { DeviceRepository } from '../../../src/database/repositories/device' +import concrete_device from './concrete_device.spec' +import { EntityData } from '@crosslab/service-common' + +export const deviceNames = ['concrete device'] as const +export type DeviceName = (typeof deviceNames)[number] +export type DeviceData = Record> + +export const deviceData: DeviceData = { + 'concrete device': concrete_device, +} diff --git a/services/device/test/data/index.spec.ts b/services/device/test/data/index.spec.ts index 865c7177..bb0920e1 100644 --- a/services/device/test/data/index.spec.ts +++ b/services/device/test/data/index.spec.ts @@ -1,7 +1,7 @@ import { DeviceRepository } from '../../src/database/repositories/device' import { PeerconnectionRepository } from '../../src/database/repositories/peerconnection' -import { deviceData, DeviceName } from './device.spec' -import { peerconnectionData, PeerconnectionName } from './peerconnection.spec' +import { deviceData, DeviceName } from './devices/index.spec' +import { peerconnectionData, PeerconnectionName } from './peerconnections/index.spec' import { GenericTestData } from '@crosslab/service-common' export type TestData = GenericTestData< diff --git a/services/device/test/data/peerconnection.spec.ts b/services/device/test/data/peerconnection.spec.ts deleted file mode 100644 index f8f24261..00000000 --- a/services/device/test/data/peerconnection.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { PeerconnectionRepository } from '../../src/database/repositories/peerconnection' -import { EntityData } from '@crosslab/service-common' - -export const peerconnectionNames = ['example peerconnection'] as const -export type PeerconnectionName = (typeof peerconnectionNames)[number] -export type PeerconnectionData = Record< - PeerconnectionName, - EntityData -> - -export const peerconnectionData: PeerconnectionData = { - 'example peerconnection': { - request: { - type: 'webrtc', - devices: [ - { url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb' }, - { url: 'http://localhost/devices/aa3272e6-6f4e-4d5b-a4a9-252d9bac9bd3' }, - ], - }, - model: { - uuid: '184f5ada-84fe-4d33-ab7d-22801be1a4ff', - type: 'webrtc', - status: 'waiting-for-devices', - deviceA: { - url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', - }, - deviceB: { - url: 'http://localhost/devices/aa3272e6-6f4e-4d5b-a4a9-252d9bac9bd3', - }, - }, - response: { - url: 'http://localhost/peeerconnections/184f5ada-84fe-4d33-ab7d-22801be1a4ff', - type: 'webrtc', - status: 'waiting-for-devices', - devices: [ - { url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb' }, - { url: 'http://localhost/devices/aa3272e6-6f4e-4d5b-a4a9-252d9bac9bd3' }, - ], - }, - }, -} diff --git a/services/device/test/data/peerconnections/example_peerconnection.spec.ts b/services/device/test/data/peerconnections/example_peerconnection.spec.ts new file mode 100644 index 00000000..b327d7f6 --- /dev/null +++ b/services/device/test/data/peerconnections/example_peerconnection.spec.ts @@ -0,0 +1,31 @@ +import { PeerconnectionRepository } from '../../../src/database/repositories/peerconnection' +import { EntityData } from '@crosslab/service-common' + +const uuid = '184f5ada-84fe-4d33-ab7d-22801be1a4ff' +const url = `http://localhost/peeerconnections/${uuid}` +const type = 'webrtc' +const urlDeviceA = 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb' +const urlDeviceB = 'http://localhost/devices/aa3272e6-6f4e-4d5b-a4a9-252d9bac9bd3' +const status = 'waiting-for-devices' + +const example_peerconnection: EntityData = { + request: { + type, + devices: [{ url: urlDeviceA }, { url: urlDeviceB }], + }, + model: { + uuid, + type, + status, + deviceA: { url: urlDeviceA }, + deviceB: { url: urlDeviceB }, + }, + response: { + url, + type, + status, + devices: [{ url: urlDeviceA }, { url: urlDeviceB }], + }, +} + +export default example_peerconnection diff --git a/services/device/test/data/peerconnections/index.spec.ts b/services/device/test/data/peerconnections/index.spec.ts new file mode 100644 index 00000000..ffb4aefd --- /dev/null +++ b/services/device/test/data/peerconnections/index.spec.ts @@ -0,0 +1,14 @@ +import { PeerconnectionRepository } from '../../../src/database/repositories/peerconnection' +import example_peerconnection from './example_peerconnection.spec' +import { EntityData } from '@crosslab/service-common' + +export const peerconnectionNames = ['example peerconnection'] as const +export type PeerconnectionName = (typeof peerconnectionNames)[number] +export type PeerconnectionData = Record< + PeerconnectionName, + EntityData +> + +export const peerconnectionData: PeerconnectionData = { + 'example peerconnection': example_peerconnection, +} diff --git a/services/device/test/database/repositories/index.spec.ts b/services/device/test/database/repositories/index.spec.ts index 7c26bb01..63e3239c 100644 --- a/services/device/test/database/repositories/index.spec.ts +++ b/services/device/test/database/repositories/index.spec.ts @@ -12,7 +12,7 @@ import { deviceRepository } from '../../../src/database/repositories/device' import { peerconnectionRepository } from '../../../src/database/repositories/peerconnection' import { deviceNames } from '../../data/device.spec' import { prepareTestData, TestData } from '../../data/index.spec' -import { peerconnectionNames } from '../../data/peerconnection.spec' +import { peerconnectionNames } from '../../data/peerconnections/index.spec' import { deviceRepositoryTestSuite } from './device.spec' import { peerconnectionRepositoryTestSuite } from './peerconnection.spec' import { DataSourceOptions } from 'typeorm' diff --git a/services/device/test/database/repositories/peerconnection.spec.ts b/services/device/test/database/repositories/peerconnection.spec.ts index 9f3c0b1a..ae71bde5 100644 --- a/services/device/test/database/repositories/peerconnection.spec.ts +++ b/services/device/test/database/repositories/peerconnection.spec.ts @@ -5,7 +5,7 @@ import { PeerconnectionRepository, } from '../../../src/database/repositories/peerconnection' import { Peerconnection } from '../../../src/generated/types' -import { PeerconnectionName } from '../../data/peerconnection.spec' +import { PeerconnectionName } from '../../data/peerconnections/index.spec' import { initTestDatabase } from './index.spec' import { AbstractRepositoryTestSuite } from '@crosslab/service-common' import { FindOptionsWhere } from 'typeorm' From 0b38e46e1cf77f29a1a2a5980984015216c29396 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 21 Mar 2023 19:03:24 +0100 Subject: [PATCH 07/33] Small changes to AbstractRepository/-TestSuite - Add possibility to remove suites - WIP: Change input to write function to Partial because it caused problems with type inference --- services/common/src/database/abstractRepository.ts | 2 +- .../src/database/testSuites/abstractRepository.spec.ts | 6 ++++++ services/common/src/database/testSuites/write.spec.ts | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/services/common/src/database/abstractRepository.ts b/services/common/src/database/abstractRepository.ts index bfa12f6f..04f23841 100644 --- a/services/common/src/database/abstractRepository.ts +++ b/services/common/src/database/abstractRepository.ts @@ -43,7 +43,7 @@ export abstract class AbstractRepository< return model; } - abstract write(model: M, data: RQ): Promise; + abstract write(model: M, data: Partial): Promise; public async save(model: M): Promise { if (!this.repository) this.throwUninitializedRepositoryError(); diff --git a/services/common/src/database/testSuites/abstractRepository.spec.ts b/services/common/src/database/testSuites/abstractRepository.spec.ts index d1edec9c..57d808eb 100644 --- a/services/common/src/database/testSuites/abstractRepository.spec.ts +++ b/services/common/src/database/testSuites/abstractRepository.spec.ts @@ -92,6 +92,12 @@ export abstract class AbstractRepositoryTestSuite< this.testSuites[suiteName] = suite(this.repositoryTestData); } + public removeSuite(suiteName: SuiteName) { + if (!this.testSuites || !this.repositoryTestData) + throw new Error('Test suite has not been initialized'); + delete this.testSuites[suiteName]; + } + protected async resetDatabase() { if (this.AppDataSource.connected) { await this.AppDataSource.teardown(); diff --git a/services/common/src/database/testSuites/write.spec.ts b/services/common/src/database/testSuites/write.spec.ts index 8e1dd614..4ec8e5c1 100644 --- a/services/common/src/database/testSuites/write.spec.ts +++ b/services/common/src/database/testSuites/write.spec.ts @@ -2,7 +2,7 @@ import assert from 'assert'; import Mocha from 'mocha'; import {AbstractRepository} from '../abstractRepository'; -import {ModelType, RepositoryTestData} from './types.spec'; +import {ModelType, RepositoryTestData, RequestType} from './types.spec'; export function testSuiteWrite< K extends string, @@ -19,7 +19,7 @@ export function testSuiteWrite< assert(repositoryTestData.validateCreate(model)); await repositoryTestData.repository.write( model, - repositoryTestData.entityData[key].request, + repositoryTestData.entityData[key].request as Partial>, ); assert( repositoryTestData.validateWrite( From 5fa03e9e698e64e03232b006c19076231bf2dbd4 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 21 Mar 2023 19:07:24 +0100 Subject: [PATCH 08/33] Small bugfixes for schema generation and client --- .../src/filters/typescript/index.ts | 24 ++++--- .../src/filters/typescript/resolve.ts | 4 +- .../filters/typescript/schemas/userType.ts | 2 +- .../src/filters/typescript/typings.ts | 5 +- .../src/filters/typescript/validation.ts | 4 +- helper/crosslab-typescript-addon/src/index.ts | 30 ++++---- .../templates/client/signatures.ts.njk | 3 + .../templates/client/types.ts.njk | 71 +++++++++++++++++++ 8 files changed, 113 insertions(+), 30 deletions(-) diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/index.ts b/helper/crosslab-typescript-addon/src/filters/typescript/index.ts index 2e59e14d..411f230c 100644 --- a/helper/crosslab-typescript-addon/src/filters/typescript/index.ts +++ b/helper/crosslab-typescript-addon/src/filters/typescript/index.ts @@ -1,4 +1,3 @@ -import { OpenAPIV3_1 } from 'openapi-types' import { formatName, formatOperation, formatExpressPath } from './format' import { ExtendedSchema, @@ -11,6 +10,7 @@ import { import { destructureSchema, schemaToTypeDeclaration } from './typings' import { validation_filter } from './validation' import { FilterCollection } from '@cross-lab-project/openapi-codegen' +import { OpenAPIV3_1 } from 'openapi-types' import { format } from 'prettier' /** @@ -359,19 +359,21 @@ function append_filter(array: any[], value: any) { array.push(value) } -function getPossibleScopeCombinations(security?: OpenAPIV3_1.SecurityRequirementObject[]) { - const possibleCombinations: [string,string][][] = [] +function getPossibleScopeCombinations( + security?: OpenAPIV3_1.SecurityRequirementObject[] +) { + const possibleCombinations: [string, string][][] = [] for (const securityRequirement of security ?? []) { - let combinations: [string,string][][] = [] + let combinations: [string, string][][] = [] for (const key in securityRequirement) { const scopes = securityRequirement[key] if (combinations.length === 0) { for (const scope of scopes) { - combinations.push([[key,scope]]) + combinations.push([[key, scope]]) } } else { for (const scope of scopes) { - combinations = combinations.map((comb) => [...comb,[key,scope]]) + combinations = combinations.map((comb) => [...comb, [key, scope]]) } } } @@ -497,19 +499,19 @@ export const TypeScriptFilterCollection: FilterCollection = { }, { name: 'includes', - function: includes_filter + function: includes_filter, }, { name: 'addProperty', - function: addProperty_filter + function: addProperty_filter, }, { name: 'append', - function: append_filter + function: append_filter, }, { name: 'possibleScopeCombinations', - function: getPossibleScopeCombinations - } + function: getPossibleScopeCombinations, + }, ], } diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts b/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts index da0b133b..75cc5fa0 100644 --- a/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts +++ b/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts @@ -394,7 +394,7 @@ export function resolveSchemas( ), '' ) - .replace(/,,/g, '') + .replace(/,,+/g, ',') .replace(/,}/g, '}') .replace(/{,/g, '{') .replace(/"\$ref":"(.*?)"/g, '"$ref":"$1_request"') @@ -408,7 +408,7 @@ export function resolveSchemas( ), '' ) - .replace(/,,/g, '') + .replace(/,,+/g, ',') .replace(/,}/g, '}') .replace(/{,/g, '{') .replace(/"\$ref":"(.*?)"/g, '"$ref":"$1_response"') diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/schemas/userType.ts b/helper/crosslab-typescript-addon/src/filters/typescript/schemas/userType.ts index 90d07d07..77694b24 100644 --- a/helper/crosslab-typescript-addon/src/filters/typescript/schemas/userType.ts +++ b/helper/crosslab-typescript-addon/src/filters/typescript/schemas/userType.ts @@ -3,7 +3,7 @@ import { OpenAPIV3_1 } from 'openapi-types' /** * Schema for the type UserType. */ -export const userTypeSchema = { +export const userTypeSchema: OpenAPIV3_1.SchemaObject & { 'x-typeguard': boolean } = { title: 'User Type', type: 'object', properties: { diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts b/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts index 936c31a8..461d96d0 100644 --- a/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts +++ b/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts @@ -290,7 +290,10 @@ export function schemaToTypeDeclaration( } return { - typeDeclaration: `SizedTuple<${td.typeDeclaration},${min},${max}>`, + typeDeclaration: + min !== 'undefined' || max !== 'undefined' + ? `SizedTuple<${td.typeDeclaration},${min},${max}>` + : `${td.typeDeclaration}[]`, typeDependencies: td.typeDependencies, comment: comment, } diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts b/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts index e0c3c67c..bee20d6d 100644 --- a/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts +++ b/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts @@ -1,8 +1,8 @@ +import { ExtendedSchema } from './resolve' import Ajv from 'ajv' +import addFormats from 'ajv-formats' // import { format } from 'prettier' import standaloneCode from 'ajv/dist/standalone' -import addFormats from 'ajv-formats' -import { ExtendedSchema } from './resolve' /** * This function defines a filter which can be used to generate the basic schema diff --git a/helper/crosslab-typescript-addon/src/index.ts b/helper/crosslab-typescript-addon/src/index.ts index 8b8750d9..73f323a3 100644 --- a/helper/crosslab-typescript-addon/src/index.ts +++ b/helper/crosslab-typescript-addon/src/index.ts @@ -1,9 +1,9 @@ import { TypeScriptFilterCollection } from './filters/typescript' -import { Addon } from '@cross-lab-project/openapi-codegen' import { attributeEqualTo } from './tests' +import { Addon } from '@cross-lab-project/openapi-codegen' import path from 'path' -const templateDir=path.resolve(__dirname, '../../') +const templateDir = path.resolve(__dirname, '../../') const CrosslabTypeScriptAddon: Addon = { filterCollections: [TypeScriptFilterCollection], @@ -12,35 +12,39 @@ const CrosslabTypeScriptAddon: Addon = { name: 'service', filterCollections: [TypeScriptFilterCollection], globals: [], - tests: [{ - name: "attrequalto", - function: attributeEqualTo - }], + tests: [ + { + name: 'attrequalto', + function: attributeEqualTo, + }, + ], templatesDir: templateDir + '/templates/service', }, { name: 'client', filterCollections: [TypeScriptFilterCollection], globals: [], - tests: [{ - name: "attrequalto", - function: attributeEqualTo - }], - templatesDir: templateDir + '/templates/client' + tests: [ + { + name: 'attrequalto', + function: attributeEqualTo, + }, + ], + templatesDir: templateDir + '/templates/client', }, { name: 'client:basicValidation', filterCollections: [TypeScriptFilterCollection], globals: [], tests: [], - templatesDir: templateDir + '/templates/client-basicValidation' + templatesDir: templateDir + '/templates/client-basicValidation', }, { name: 'service:test', filterCollections: [TypeScriptFilterCollection], globals: [], tests: [], - templatesDir: templateDir + '/templates/service-test' + templatesDir: templateDir + '/templates/service-test', }, { name: 'scopes', diff --git a/helper/crosslab-typescript-addon/templates/client/signatures.ts.njk b/helper/crosslab-typescript-addon/templates/client/signatures.ts.njk index 641ecdb7..cf79e419 100644 --- a/helper/crosslab-typescript-addon/templates/client/signatures.ts.njk +++ b/helper/crosslab-typescript-addon/templates/client/signatures.ts.njk @@ -174,5 +174,8 @@ export namespace {{ serviceName | formatName }}Signatures { {%- if content | includes("Require<") -%} {%- set content = content | replace('import {', 'import {\n\tRequire,') -%} {%- endif -%} +{%- if content | includes("SizedTuple<") -%} + {%- set content = content | replace('import {', 'import {\n\tSizedTuple,') -%} +{%- endif -%} {{ content | prettier }} \ No newline at end of file diff --git a/helper/crosslab-typescript-addon/templates/client/types.ts.njk b/helper/crosslab-typescript-addon/templates/client/types.ts.njk index 62fc5bf4..d25cc0cf 100644 --- a/helper/crosslab-typescript-addon/templates/client/types.ts.njk +++ b/helper/crosslab-typescript-addon/templates/client/types.ts.njk @@ -75,6 +75,77 @@ export type Require = Partial & { [Property in Key]-?: Type[Property] } +export type SizedTuple< + T, + MIN extends number | undefined = undefined, + MAX extends number | undefined = undefined +> = MIN extends number + ? MAX extends number + ? _SizedTuple> + : TupleObject> & T[] + : MAX extends number + ? _SizedTuple, true> + : T[]; + +type _SizedTuple< + T, + ARR extends number[], + Z extends boolean = false +> = ARR extends [infer HEAD extends number, ...infer TAIL extends number[]] + ? Tuple | _SizedTuple + : never; + +type Tuple = _Tuple< + T, + NumericRangeTuple +>; + +type _Tuple = N extends [ + infer HEAD, + ...infer TAIL extends number[] +] + ? HEAD extends 0 + ? [] | _Tuple + : [T, ..._Tuple] + : []; + +type TupleObject = N extends [ + infer HEAD extends number, + ...infer TAIL extends number[] +] + ? TAIL extends [] + ? {} + : { [P in HEAD]: T } & TupleObject + : {}; + +export type NumericRange< + START extends number, + END extends number, + ARR extends unknown[] = [], + ACC extends number = never +> = ARR['length'] extends END + ? ACC | START | END + : NumericRange< + START, + END, + [...ARR, 1], + ARR[START] extends undefined ? ACC : ACC | ARR['length'] + >; + +type NumericRangeTuple< + START extends number, + END extends number, + ARR extends unknown[] = [], + ACC extends number[] = [] +> = ARR['length'] extends END + ? [START, ...ACC, END] + : NumericRangeTuple< + START, + END, + [...ARR, 1], + ARR[START] extends undefined ? ACC : [...ACC, ARR['length']] + >; + {%- for serviceName, schemas in sortedSchemas %} /** From eaa8087f1c3a04b1517eaab2930a3e01ee94e186 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 21 Mar 2023 19:08:29 +0100 Subject: [PATCH 09/33] WIP: Restructuring and Database Tests - Start writing repository test suites - Add Init and Update Device Types - Add example device data for tests --- services/device/.gitignore | 3 +- services/device/.prettierrc | 3 +- services/device/api/content/device_init.yml | 2 +- .../{device_body.yml => device_update.yml} | 2 +- services/device/api/resources/device.yml | 2 +- .../devices/device_cloud_instantiable.yml | 2 + .../api/schemas/devices/device_concrete.yml | 2 + .../devices/device_edge_instantiable.yml | 2 + .../api/schemas/devices/device_group.yml | 2 + .../api/schemas/devices/device_init.yml | 35 - .../api/schemas/devices/device_overview.yml | 1 + .../init/device_cloud_instantiable_init.yml | 20 + .../devices/init/device_concrete_init.yml | 20 + .../init/device_edge_instantiable_init.yml | 20 + .../devices/init/device_group_init.yml | 16 + .../api/schemas/devices/init/device_init.yml | 7 + .../devices/init/device_overview_init.yml | 23 + .../device_cloud_instantiable_update.yml | 15 + .../devices/update/device_concrete_update.yml | 15 + .../device_edge_instantiable_update.yml | 15 + .../devices/update/device_group_update.yml | 11 + .../devices/update/device_overview_update.yml | 12 + .../schemas/devices/update/device_update.yml | 7 + services/device/dist/openapi.json | 442 +++-- services/device/package-lock.json | 1444 ++++++++++++++++- services/device/package.json | 12 +- services/device/src/database/dataSource.ts | 8 + services/device/src/database/model.ts | 2 +- .../src/database/repositories/device.ts | 60 +- .../repositories/device/concreteDevice.ts | 14 +- .../repositories/device/deviceGroup.ts | 23 +- .../repositories/device/deviceOverview.ts | 5 +- .../device/instantiableBrowserDevice.ts | 16 +- .../device/instantiableCloudDevice.ts | 16 +- services/device/src/operations/devices/get.ts | 4 +- .../concrete_device.spec.ts | 4 +- .../devices/concreteDevices/index.spec.ts | 14 + .../devices/deviceGroups/device_group.spec.ts | 36 + .../data/devices/deviceGroups/index.spec.ts | 11 + .../device/test/data/devices/index.spec.ts | 36 +- .../instantiableBrowserDevices/index.spec.ts | 15 + .../instantiable_browser_device.spec.ts | 36 + .../instantiableCloudDevices/index.spec.ts | 14 + .../instantiable_cloud_device.spec.ts | 36 + services/device/test/data/index.spec.ts | 37 +- services/device/test/database/index.spec.ts | 16 + .../test/database/repositories/device.spec.ts | 200 ++- .../device/concreteDevice.spec.ts | 130 ++ .../repositories/device/deviceGroup.spec.ts | 95 ++ .../device/deviceOverview.spec.ts | 82 + .../device/instantiableBrowserDevice.spec.ts | 114 ++ .../device/instantiableCloudDevice.spec.ts | 114 ++ .../test/database/repositories/index.spec.ts | 2 +- services/openapi/dist/openapi.json | 680 +++++--- 54 files changed, 3499 insertions(+), 456 deletions(-) rename services/device/api/content/{device_body.yml => device_update.yml} (80%) delete mode 100644 services/device/api/schemas/devices/device_init.yml create mode 100644 services/device/api/schemas/devices/init/device_cloud_instantiable_init.yml create mode 100644 services/device/api/schemas/devices/init/device_concrete_init.yml create mode 100644 services/device/api/schemas/devices/init/device_edge_instantiable_init.yml create mode 100644 services/device/api/schemas/devices/init/device_group_init.yml create mode 100644 services/device/api/schemas/devices/init/device_init.yml create mode 100644 services/device/api/schemas/devices/init/device_overview_init.yml create mode 100644 services/device/api/schemas/devices/update/device_cloud_instantiable_update.yml create mode 100644 services/device/api/schemas/devices/update/device_concrete_update.yml create mode 100644 services/device/api/schemas/devices/update/device_edge_instantiable_update.yml create mode 100644 services/device/api/schemas/devices/update/device_group_update.yml create mode 100644 services/device/api/schemas/devices/update/device_overview_update.yml create mode 100644 services/device/api/schemas/devices/update/device_update.yml rename services/device/test/data/devices/{ => concreteDevices}/concrete_device.spec.ts (80%) create mode 100644 services/device/test/data/devices/concreteDevices/index.spec.ts create mode 100644 services/device/test/data/devices/deviceGroups/device_group.spec.ts create mode 100644 services/device/test/data/devices/deviceGroups/index.spec.ts create mode 100644 services/device/test/data/devices/instantiableBrowserDevices/index.spec.ts create mode 100644 services/device/test/data/devices/instantiableBrowserDevices/instantiable_browser_device.spec.ts create mode 100644 services/device/test/data/devices/instantiableCloudDevices/index.spec.ts create mode 100644 services/device/test/data/devices/instantiableCloudDevices/instantiable_cloud_device.spec.ts create mode 100644 services/device/test/database/repositories/device/concreteDevice.spec.ts create mode 100644 services/device/test/database/repositories/device/deviceGroup.spec.ts create mode 100644 services/device/test/database/repositories/device/deviceOverview.spec.ts create mode 100644 services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts create mode 100644 services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts diff --git a/services/device/.gitignore b/services/device/.gitignore index 974bb885..6e936f86 100644 --- a/services/device/.gitignore +++ b/services/device/.gitignore @@ -6,4 +6,5 @@ node_modules *.db package.resolved.json .packages -app \ No newline at end of file +app +.nyc_output \ No newline at end of file diff --git a/services/device/.prettierrc b/services/device/.prettierrc index aebbafb7..6a023956 100644 --- a/services/device/.prettierrc +++ b/services/device/.prettierrc @@ -5,5 +5,6 @@ "semi": false, "singleQuote": true, "printWidth": 90, - "importOrderParserPlugins": ["typescript", "decorators-legacy"] + "importOrderParserPlugins": ["typescript", "decorators-legacy"], + "quoteProps": "consistent" } \ No newline at end of file diff --git a/services/device/api/content/device_init.yml b/services/device/api/content/device_init.yml index 3289f4cd..103a5eca 100644 --- a/services/device/api/content/device_init.yml +++ b/services/device/api/content/device_init.yml @@ -1,6 +1,6 @@ # yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json schema: - $ref: ../schemas/devices/device_init.yml + $ref: ../schemas/devices/init/device_init.yml examples: microcontroller: value: diff --git a/services/device/api/content/device_body.yml b/services/device/api/content/device_update.yml similarity index 80% rename from services/device/api/content/device_body.yml rename to services/device/api/content/device_update.yml index 1fb04f58..c73a4012 100644 --- a/services/device/api/content/device_body.yml +++ b/services/device/api/content/device_update.yml @@ -1,6 +1,6 @@ # yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json schema: - $ref: ../schemas/devices/device.yml + $ref: ../schemas/devices/update/device_update.yml examples: microcontroller: value: diff --git a/services/device/api/resources/device.yml b/services/device/api/resources/device.yml index 078324c5..85efb1f3 100644 --- a/services/device/api/resources/device.yml +++ b/services/device/api/resources/device.yml @@ -43,7 +43,7 @@ patch: description: Updated device. content: application/json: - $ref: "../content/device_body.yml" + $ref: "../content/device_update.yml" responses: 200: description: The JSON Representation of the changed device. diff --git a/services/device/api/schemas/devices/device_cloud_instantiable.yml b/services/device/api/schemas/devices/device_cloud_instantiable.yml index 06467303..93bec0f3 100644 --- a/services/device/api/schemas/devices/device_cloud_instantiable.yml +++ b/services/device/api/schemas/devices/device_cloud_instantiable.yml @@ -13,4 +13,6 @@ allOf: type: array items: $ref: ./services/service_description.yml + required: + - type x-typeguard: true diff --git a/services/device/api/schemas/devices/device_concrete.yml b/services/device/api/schemas/devices/device_concrete.yml index 49cd6f03..372a8584 100644 --- a/services/device/api/schemas/devices/device_concrete.yml +++ b/services/device/api/schemas/devices/device_concrete.yml @@ -21,4 +21,6 @@ allOf: type: array items: $ref: ./services/service_description.yml + required: + - type x-typeguard: true diff --git a/services/device/api/schemas/devices/device_edge_instantiable.yml b/services/device/api/schemas/devices/device_edge_instantiable.yml index 8e3ff43f..ce800e6e 100644 --- a/services/device/api/schemas/devices/device_edge_instantiable.yml +++ b/services/device/api/schemas/devices/device_edge_instantiable.yml @@ -13,4 +13,6 @@ allOf: type: array items: $ref: ./services/service_description.yml + required: + - type x-typeguard: true diff --git a/services/device/api/schemas/devices/device_group.yml b/services/device/api/schemas/devices/device_group.yml index de61e320..46b99f57 100644 --- a/services/device/api/schemas/devices/device_group.yml +++ b/services/device/api/schemas/devices/device_group.yml @@ -10,4 +10,6 @@ allOf: type: array items: $ref: ./device_reference.yml + required: + - type x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/devices/device_init.yml b/services/device/api/schemas/devices/device_init.yml deleted file mode 100644 index d748206f..00000000 --- a/services/device/api/schemas/devices/device_init.yml +++ /dev/null @@ -1,35 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -title: Device Init -anyOf: - - allOf: - - $ref: './device_concrete.yml' - - type: object - properties: - type: - const: device - required: - - type - - allOf: - - $ref: './device_group.yml' - - type: object - properties: - type: - const: group - required: - - type - - allOf: - - $ref: './device_cloud_instantiable.yml' - - type: object - properties: - type: - const: cloud instantiable - required: - - type - - allOf: - - $ref: './device_edge_instantiable.yml' - - type: object - properties: - type: - const: edge instantiable - required: - - type \ No newline at end of file diff --git a/services/device/api/schemas/devices/device_overview.yml b/services/device/api/schemas/devices/device_overview.yml index e8099993..fbdb477e 100644 --- a/services/device/api/schemas/devices/device_overview.yml +++ b/services/device/api/schemas/devices/device_overview.yml @@ -27,4 +27,5 @@ properties: readOnly: true required: - url + - type x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/devices/init/device_cloud_instantiable_init.yml b/services/device/api/schemas/devices/init/device_cloud_instantiable_init.yml new file mode 100644 index 00000000..f3470b22 --- /dev/null +++ b/services/device/api/schemas/devices/init/device_cloud_instantiable_init.yml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Instantiable Cloud Device Init +allOf: + - $ref: ./device_overview_init.yml + - type: object + properties: + type: + const: cloud instantiable + writeOnly: true + instantiateUrl: + type: string + format: uri + writeOnly: true + services: + type: array + items: + $ref: ../services/service_description.yml + writeOnly: true + required: + - type diff --git a/services/device/api/schemas/devices/init/device_concrete_init.yml b/services/device/api/schemas/devices/init/device_concrete_init.yml new file mode 100644 index 00000000..6129952b --- /dev/null +++ b/services/device/api/schemas/devices/init/device_concrete_init.yml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Concrete Device Init +allOf: + - $ref: ./device_overview_init.yml + - type: object + properties: + type: + const: device + writeOnly: true + experiment: + type: string + format: uri + writeOnly: true + services: + type: array + items: + $ref: ../services/service_description.yml + writeOnly: true + required: + - type diff --git a/services/device/api/schemas/devices/init/device_edge_instantiable_init.yml b/services/device/api/schemas/devices/init/device_edge_instantiable_init.yml new file mode 100644 index 00000000..9805a1cc --- /dev/null +++ b/services/device/api/schemas/devices/init/device_edge_instantiable_init.yml @@ -0,0 +1,20 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Instantiable Browser Device Init +allOf: + - $ref: ./device_overview_init.yml + - type: object + properties: + type: + const: edge instantiable + writeOnly: true + codeUrl: + type: string + format: uri + writeOnly: true + services: + type: array + items: + $ref: ../services/service_description.yml + writeOnly: true + required: + - type \ No newline at end of file diff --git a/services/device/api/schemas/devices/init/device_group_init.yml b/services/device/api/schemas/devices/init/device_group_init.yml new file mode 100644 index 00000000..c4fe9d7e --- /dev/null +++ b/services/device/api/schemas/devices/init/device_group_init.yml @@ -0,0 +1,16 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Device Group Init +allOf: + - $ref: ./device_overview_init.yml + - type: object + properties: + type: + const: group + writeOnly: true + devices: + type: array + items: + $ref: ../device_reference.yml + writeOnly: true + required: + - type \ No newline at end of file diff --git a/services/device/api/schemas/devices/init/device_init.yml b/services/device/api/schemas/devices/init/device_init.yml new file mode 100644 index 00000000..20c72304 --- /dev/null +++ b/services/device/api/schemas/devices/init/device_init.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Device Init +oneOf: + - $ref: ./device_cloud_instantiable_init.yml + - $ref: ./device_concrete_init.yml + - $ref: ./device_edge_instantiable_init.yml + - $ref: ./device_group_init.yml \ No newline at end of file diff --git a/services/device/api/schemas/devices/init/device_overview_init.yml b/services/device/api/schemas/devices/init/device_overview_init.yml new file mode 100644 index 00000000..734acbc4 --- /dev/null +++ b/services/device/api/schemas/devices/init/device_overview_init.yml @@ -0,0 +1,23 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Device Overview Init +type: object +properties: + name: + type: string + description: Name of the device + writeOnly: true + description: + type: string + description: Extended description of the device, features, etc. + writeOnly: true + type: + type: string + description: Type of the device + enum: + - device + - group + - edge instantiable + - cloud instantiable + writeOnly: true +required: + - type \ No newline at end of file diff --git a/services/device/api/schemas/devices/update/device_cloud_instantiable_update.yml b/services/device/api/schemas/devices/update/device_cloud_instantiable_update.yml new file mode 100644 index 00000000..097f8204 --- /dev/null +++ b/services/device/api/schemas/devices/update/device_cloud_instantiable_update.yml @@ -0,0 +1,15 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Instantiable Cloud Device Update +allOf: + - $ref: ./device_overview_update.yml + - type: object + properties: + instantiateUrl: + type: string + format: uri + writeOnly: true + services: + type: array + items: + $ref: ../services/service_description.yml + writeOnly: true diff --git a/services/device/api/schemas/devices/update/device_concrete_update.yml b/services/device/api/schemas/devices/update/device_concrete_update.yml new file mode 100644 index 00000000..3ecd1d6a --- /dev/null +++ b/services/device/api/schemas/devices/update/device_concrete_update.yml @@ -0,0 +1,15 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Concrete Device Update +allOf: + - $ref: ./device_overview_update.yml + - type: object + properties: + experiment: + type: string + format: uri + writeOnly: true + services: + type: array + items: + $ref: ../services/service_description.yml + writeOnly: true diff --git a/services/device/api/schemas/devices/update/device_edge_instantiable_update.yml b/services/device/api/schemas/devices/update/device_edge_instantiable_update.yml new file mode 100644 index 00000000..6c5b8f2a --- /dev/null +++ b/services/device/api/schemas/devices/update/device_edge_instantiable_update.yml @@ -0,0 +1,15 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Instantiable Browser Device Update +allOf: + - $ref: ./device_overview_update.yml + - type: object + properties: + codeUrl: + type: string + format: uri + writeOnly: true + services: + type: array + items: + $ref: ../services/service_description.yml + writeOnly: true diff --git a/services/device/api/schemas/devices/update/device_group_update.yml b/services/device/api/schemas/devices/update/device_group_update.yml new file mode 100644 index 00000000..8e92509b --- /dev/null +++ b/services/device/api/schemas/devices/update/device_group_update.yml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Device Group Update +allOf: + - $ref: ./device_overview_update.yml + - type: object + properties: + devices: + type: array + items: + $ref: ../device_reference.yml + writeOnly: true \ No newline at end of file diff --git a/services/device/api/schemas/devices/update/device_overview_update.yml b/services/device/api/schemas/devices/update/device_overview_update.yml new file mode 100644 index 00000000..9493832d --- /dev/null +++ b/services/device/api/schemas/devices/update/device_overview_update.yml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Device Overview Update +type: object +properties: + name: + type: string + description: Name of the device + writeOnly: true + description: + type: string + description: Extended description of the device, features, etc. + writeOnly: true \ No newline at end of file diff --git a/services/device/api/schemas/devices/update/device_update.yml b/services/device/api/schemas/devices/update/device_update.yml new file mode 100644 index 00000000..417d14c1 --- /dev/null +++ b/services/device/api/schemas/devices/update/device_update.yml @@ -0,0 +1,7 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Device Update +oneOf: + - $ref: ./device_cloud_instantiable_update.yml + - $ref: ./device_concrete_update.yml + - $ref: ./device_edge_instantiable_update.yml + - $ref: ./device_group_update.yml \ No newline at end of file diff --git a/services/device/dist/openapi.json b/services/device/dist/openapi.json index 4f9a657a..8e97f47e 100644 --- a/services/device/dist/openapi.json +++ b/services/device/dist/openapi.json @@ -77,31 +77,40 @@ } }, "required": [ - "url" + "url", + "type" ], "x-typeguard": true }, - "time_slot": { - "title": "Time Slot", + "device_overview_init": { + "title": "Device Overview Init", "type": "object", "properties": { - "start": { + "name": { "type": "string", - "format": "date-time" + "description": "Name of the device", + "writeOnly": true }, - "end": { + "description": { "type": "string", - "format": "date-time" + "description": "Extended description of the device, features, etc.", + "writeOnly": true + }, + "type": { + "type": "string", + "description": "Type of the device", + "enum": [ + "device", + "group", + "edge instantiable", + "cloud instantiable" + ], + "writeOnly": true } - } - }, - "availability": { - "title": "Availability", - "description": "A list of time slots that the maintainer of the device announced it is available\n", - "type": "array", - "items": { - "$ref": "#/components/schemas/time_slot" - } + }, + "required": [ + "type" + ] }, "service_description": { "title": "Service Description", @@ -125,41 +134,101 @@ }, "additionalProperties": true }, - "device_concrete": { - "title": "Concrete Device", + "device_cloud_instantiable_init": { + "title": "Instantiable Cloud Device Init", "allOf": [ { - "$ref": "#/components/schemas/device_overview" + "$ref": "#/components/schemas/device_overview_init" }, { "type": "object", "properties": { "type": { - "const": "device" + "const": "cloud instantiable", + "writeOnly": true }, - "connected": { - "description": "If true, the device is connected to the service and can be used.\n", - "type": "boolean", - "readOnly": true + "instantiateUrl": { + "type": "string", + "format": "uri", + "writeOnly": true }, - "announcedAvailability": { - "$ref": "#/components/schemas/availability", - "readOnly": true + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + }, + "writeOnly": true + } + }, + "required": [ + "type" + ] + } + ] + }, + "device_concrete_init": { + "title": "Concrete Device Init", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_init" + }, + { + "type": "object", + "properties": { + "type": { + "const": "device", + "writeOnly": true }, "experiment": { "type": "string", - "format": "uri" + "format": "uri", + "writeOnly": true }, "services": { "type": "array", "items": { "$ref": "#/components/schemas/service_description" - } + }, + "writeOnly": true } - } + }, + "required": [ + "type" + ] } - ], - "x-typeguard": true + ] + }, + "device_edge_instantiable_init": { + "title": "Instantiable Browser Device Init", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_init" + }, + { + "type": "object", + "properties": { + "type": { + "const": "edge instantiable", + "writeOnly": true + }, + "codeUrl": { + "type": "string", + "format": "uri", + "writeOnly": true + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + }, + "writeOnly": true + } + }, + "required": [ + "type" + ] + } + ] }, "device_reference": { "title": "Device Reference", @@ -175,28 +244,49 @@ "url" ] }, - "device_group": { - "title": "Device Group", + "device_group_init": { + "title": "Device Group Init", "allOf": [ { - "$ref": "#/components/schemas/device_overview" + "$ref": "#/components/schemas/device_overview_init" }, { "type": "object", "properties": { "type": { - "const": "group" + "const": "group", + "writeOnly": true }, "devices": { "type": "array", "items": { "$ref": "#/components/schemas/device_reference" - } + }, + "writeOnly": true } - } + }, + "required": [ + "type" + ] } - ], - "x-typeguard": true + ] + }, + "device_init": { + "title": "Device Init", + "oneOf": [ + { + "$ref": "#/components/schemas/device_cloud_instantiable_init" + }, + { + "$ref": "#/components/schemas/device_concrete_init" + }, + { + "$ref": "#/components/schemas/device_edge_instantiable_init" + }, + { + "$ref": "#/components/schemas/device_group_init" + } + ] }, "device_cloud_instantiable": { "title": "Instantiable Cloud Device", @@ -220,7 +310,71 @@ "$ref": "#/components/schemas/service_description" } } - } + }, + "required": [ + "type" + ] + } + ], + "x-typeguard": true + }, + "time_slot": { + "title": "Time Slot", + "type": "object", + "properties": { + "start": { + "type": "string", + "format": "date-time" + }, + "end": { + "type": "string", + "format": "date-time" + } + } + }, + "availability": { + "title": "Availability", + "description": "A list of time slots that the maintainer of the device announced it is available\n", + "type": "array", + "items": { + "$ref": "#/components/schemas/time_slot" + } + }, + "device_concrete": { + "title": "Concrete Device", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview" + }, + { + "type": "object", + "properties": { + "type": { + "const": "device" + }, + "connected": { + "description": "If true, the device is connected to the service and can be used.\n", + "type": "boolean", + "readOnly": true + }, + "announcedAvailability": { + "$ref": "#/components/schemas/availability", + "readOnly": true + }, + "experiment": { + "type": "string", + "format": "uri" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + } + } + }, + "required": [ + "type" + ] } ], "x-typeguard": true @@ -247,102 +401,182 @@ "$ref": "#/components/schemas/service_description" } } - } + }, + "required": [ + "type" + ] } ], "x-typeguard": true }, - "device_init": { - "title": "Device Init", - "anyOf": [ + "device_group": { + "title": "Device Group", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview" + }, { - "allOf": [ - { - "$ref": "#/components/schemas/device_concrete" + "type": "object", + "properties": { + "type": { + "const": "group" }, - { - "type": "object", - "properties": { - "type": { - "const": "device" - } - }, - "required": [ - "type" - ] + "devices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/device_reference" + } } + }, + "required": [ + "type" ] + } + ], + "x-typeguard": true + }, + "device": { + "title": "Device", + "oneOf": [ + { + "$ref": "#/components/schemas/device_cloud_instantiable" + }, + { + "$ref": "#/components/schemas/device_concrete" + }, + { + "$ref": "#/components/schemas/device_edge_instantiable" + }, + { + "$ref": "#/components/schemas/device_group" + } + ] + }, + "device_overview_update": { + "title": "Device Overview Update", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the device", + "writeOnly": true + }, + "description": { + "type": "string", + "description": "Extended description of the device, features, etc.", + "writeOnly": true + } + } + }, + "device_cloud_instantiable_update": { + "title": "Instantiable Cloud Device Update", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_update" }, { - "allOf": [ - { - "$ref": "#/components/schemas/device_group" + "type": "object", + "properties": { + "instantiateUrl": { + "type": "string", + "format": "uri", + "writeOnly": true }, - { - "type": "object", - "properties": { - "type": { - "const": "group" - } + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" }, - "required": [ - "type" - ] + "writeOnly": true } - ] + } + } + ] + }, + "device_concrete_update": { + "title": "Concrete Device Update", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_update" }, { - "allOf": [ - { - "$ref": "#/components/schemas/device_cloud_instantiable" + "type": "object", + "properties": { + "experiment": { + "type": "string", + "format": "uri", + "writeOnly": true }, - { - "type": "object", - "properties": { - "type": { - "const": "cloud instantiable" - } + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" }, - "required": [ - "type" - ] + "writeOnly": true } - ] + } + } + ] + }, + "device_edge_instantiable_update": { + "title": "Instantiable Browser Device Update", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_update" }, { - "allOf": [ - { - "$ref": "#/components/schemas/device_edge_instantiable" + "type": "object", + "properties": { + "codeUrl": { + "type": "string", + "format": "uri", + "writeOnly": true }, - { - "type": "object", - "properties": { - "type": { - "const": "edge instantiable" - } + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" }, - "required": [ - "type" - ] + "writeOnly": true } - ] + } } ] }, - "device": { - "title": "Device", + "device_group_update": { + "title": "Device Group Update", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_update" + }, + { + "type": "object", + "properties": { + "devices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/device_reference" + }, + "writeOnly": true + } + } + } + ] + }, + "device_update": { + "title": "Device Update", "oneOf": [ { - "$ref": "#/components/schemas/device_cloud_instantiable" + "$ref": "#/components/schemas/device_cloud_instantiable_update" }, { - "$ref": "#/components/schemas/device_concrete" + "$ref": "#/components/schemas/device_concrete_update" }, { - "$ref": "#/components/schemas/device_edge_instantiable" + "$ref": "#/components/schemas/device_edge_instantiable_update" }, { - "$ref": "#/components/schemas/device_group" + "$ref": "#/components/schemas/device_group_update" } ] }, @@ -1319,7 +1553,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/device" + "$ref": "#/components/schemas/device_update" }, "examples": { "microcontroller": { diff --git a/services/device/package-lock.json b/services/device/package-lock.json index ba85646f..e4268635 100644 --- a/services/device/package-lock.json +++ b/services/device/package-lock.json @@ -24,6 +24,7 @@ "crosslab-device-service": "app/index.js" }, "devDependencies": { + "@babel/register": "^7.21.0", "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", "@trivago/prettier-plugin-sort-imports": "^4.0.0", @@ -39,7 +40,9 @@ "eslint": "^8.34.0", "mocha": "^10.2.0", "nodemon": "^2.0.19", + "nyc": "^15.1.0", "prettier": "^2.7.1", + "ts-mocha": "^10.0.0", "ts-node": "^10.9.1", "typescript": "^4.7.4" } @@ -610,6 +613,134 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/register": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.21.0.tgz", + "integrity": "sha512-9nKsPmYDi5DidAqJaQooxIhsLJiNMkGr8ypQ8Uic7cIox7UCDsM7HuUGxdGT7mSDTYbqzIdsOWzfBton/YJrMw==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.5", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register/node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/register/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/register/node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/register/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/@babel/template": { "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", @@ -839,6 +970,101 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", @@ -1132,6 +1358,19 @@ "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", "dev": true }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "optional": true + }, + "node_modules/@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -1670,7 +1909,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "optional": true, + "devOptional": true, "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -1765,11 +2004,29 @@ "node": ">= 6.0.0" } }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true + }, "node_modules/are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", @@ -1815,6 +2072,21 @@ "node": ">=8" } }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2052,6 +2324,21 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "optional": true }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -2166,7 +2453,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "optional": true, + "devOptional": true, "engines": { "node": ">=6" } @@ -2303,6 +2590,26 @@ "node": ">=12" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", + "dev": true + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -2338,6 +2645,21 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2457,6 +2779,21 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2622,6 +2959,60 @@ "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "optional": true }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -3162,6 +3553,23 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3206,6 +3614,19 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/form-data": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", @@ -3236,11 +3657,31 @@ "node": ">= 0.6" } }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dependencies": { + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { "minipass": "^3.0.0" }, "engines": { @@ -3306,6 +3747,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -3370,7 +3832,7 @@ "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "optional": true + "devOptional": true }, "node_modules/grapheme-splitter": { "version": "1.0.4", @@ -3414,6 +3876,43 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -3431,6 +3930,12 @@ "node": "*" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -3561,7 +4066,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "optional": true, + "devOptional": true, "engines": { "node": ">=8" } @@ -3674,6 +4179,18 @@ "node": ">=8" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", @@ -3689,6 +4206,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -3707,6 +4230,15 @@ "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", "dev": true }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3718,6 +4250,180 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "devOptional": true }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==", + "dev": true, + "dependencies": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch/node_modules/node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dev": true, + "dependencies": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/javascript-natural-sort": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", @@ -3783,6 +4489,24 @@ "node": ">=6" } }, + "node_modules/jsonpath-plus": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-5.1.0.tgz", + "integrity": "sha512-890w2Pjtj0iswAxalRlt2kHthi6HKrXEfZcn+ZNZptv7F3rUGIeDuZo+C+h4vXBHLEsVjJrHeCm35nYeZLzSBQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3817,6 +4541,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4607,6 +5337,18 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "optional": true }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/node-releases": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", @@ -4673,24 +5415,289 @@ "node": ">=6" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/nunjucks": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz", + "integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==", + "dev": true, + "dependencies": { + "a-sync-waterfall": "^1.0.0", + "asap": "^2.0.3", + "commander": "^5.1.0" + }, + "bin": { + "nunjucks-precompile": "bin/precompile" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "chokidar": "^3.3.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/nunjucks/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/nyc/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/nyc/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/nyc/node_modules/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==", + "dev": true + }, + "node_modules/nyc/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" } }, "node_modules/object-assign": { @@ -4790,6 +5797,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4886,6 +5923,97 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss": { "version": "8.4.21", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", @@ -4940,6 +6068,18 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -5176,6 +6316,18 @@ "url": "https://github.com/sponsors/mysticatea" } }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5192,6 +6344,29 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -5380,6 +6555,24 @@ "sha.js": "bin.js" } }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==", + "dev": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5506,6 +6699,25 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", @@ -5514,6 +6726,29 @@ "dev": true, "peer": true }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/sqlite3": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.4.tgz", @@ -5601,6 +6836,15 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -5654,6 +6898,20 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5740,6 +6998,79 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, + "node_modules/ts-mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", + "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", + "dev": true, + "dependencies": { + "ts-node": "7.0.1" + }, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "optionalDependencies": { + "tsconfig-paths": "^3.5.0" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X" + } + }, + "node_modules/ts-mocha/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ts-mocha/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ts-mocha/node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-mocha/node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -5783,6 +7114,42 @@ } } }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "optional": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "optional": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=4" + } + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -5840,6 +7207,21 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "node_modules/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, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, "node_modules/typeorm": { "version": "0.3.12", "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", @@ -6226,6 +7608,12 @@ "node": ">= 8" } }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", + "dev": true + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -6306,6 +7694,18 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/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, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "node_modules/ws": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz", diff --git a/services/device/package.json b/services/device/package.json index 0917affd..fb2babc0 100644 --- a/services/device/package.json +++ b/services/device/package.json @@ -19,11 +19,13 @@ "start": "node app/index.js", "dev": "env-cmd -e development npx nodemon src/index.ts", "format": "npx prettier src --write", - "lint": "eslint ." + "lint": "eslint .", + "test:database": "nyc --temp-dir .nyc_output/database --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/database/index.spec.ts" }, "author": "Johannes Nau", "license": "UNLICENSED", "devDependencies": { + "@babel/register": "^7.21.0", "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", "@trivago/prettier-plugin-sort-imports": "^4.0.0", @@ -37,11 +39,13 @@ "@typescript-eslint/parser": "^5.51.0", "env-cmd": "^10.1.0", "eslint": "^8.34.0", + "mocha": "^10.2.0", "nodemon": "^2.0.19", + "nyc": "^15.1.0", "prettier": "^2.7.1", + "ts-mocha": "^10.0.0", "ts-node": "^10.9.1", - "typescript": "^4.7.4", - "mocha": "^10.2.0" + "typescript": "^4.7.4" }, "dependencies": { "@cross-lab-project/api-client": "file:../../clients/api/js", @@ -57,4 +61,4 @@ "typeorm": "^0.3.6", "ws": "^8.8.0" } -} \ No newline at end of file +} diff --git a/services/device/src/database/dataSource.ts b/services/device/src/database/dataSource.ts index 4830da74..278c73e4 100644 --- a/services/device/src/database/dataSource.ts +++ b/services/device/src/database/dataSource.ts @@ -1,9 +1,17 @@ import { deviceRepository } from './repositories/device' +import { concreteDeviceRepository } from './repositories/device/concreteDevice' +import { deviceGroupRepository } from './repositories/device/deviceGroup' +import { instantiableBrowserDeviceRepository } from './repositories/device/instantiableBrowserDevice' +import { instantiableCloudDeviceRepository } from './repositories/device/instantiableCloudDevice' import { peerconnectionRepository } from './repositories/peerconnection' import { AbstractApplicationDataSource } from '@crosslab/service-common' class ApplicationDataSource extends AbstractApplicationDataSource { protected initializeRepositories(): void { + concreteDeviceRepository.initialize(this) + deviceGroupRepository.initialize(this) + instantiableBrowserDeviceRepository.initialize(this) + instantiableCloudDeviceRepository.initialize(this) deviceRepository.initialize(this) peerconnectionRepository.initialize(this) } diff --git a/services/device/src/database/model.ts b/services/device/src/database/model.ts index 0f240633..e69f7efb 100644 --- a/services/device/src/database/model.ts +++ b/services/device/src/database/model.ts @@ -38,7 +38,7 @@ export abstract class DeviceOverviewModel { description?: string @Column() type!: 'device' | 'group' | 'cloud instantiable' | 'edge instantiable' - @Column() + @Column({ nullable: true }) owner?: string @DeleteDateColumn() deletedAt?: Date diff --git a/services/device/src/database/repositories/device.ts b/services/device/src/database/repositories/device.ts index e2a5a22b..d4c4d121 100644 --- a/services/device/src/database/repositories/device.ts +++ b/services/device/src/database/repositories/device.ts @@ -1,11 +1,4 @@ -import { - Device, - DeviceOverview, - isConcreteDevice, - isDeviceGroup, - isInstantiableBrowserDevice, - isInstantiableCloudDevice, -} from '../../generated/types' +import { Device, DeviceInit, DeviceUpdate } from '../../generated/types' import { DeviceModel, DeviceOverviewModel } from '../model' import { concreteDeviceRepository } from './device/concreteDevice' import { deviceGroupRepository } from './device/deviceGroup' @@ -15,7 +8,6 @@ import { instantiableCloudDeviceRepository } from './device/instantiableCloudDev import { AbstractApplicationDataSource, AbstractRepository, - InvalidValueError, } from '@crosslab/service-common' export class DeviceRepository extends AbstractRepository< @@ -31,47 +23,41 @@ export class DeviceRepository extends AbstractRepository< this.repository = AppDataSource.getRepository(DeviceOverviewModel) } - async write(model: DeviceModel, data: Device<'request'>): Promise { + async create(data?: DeviceInit<'request'>): Promise { + if (!this.repository) this.throwUninitializedRepositoryError() + if (!data) return await super.create() + + switch (data.type) { + case 'cloud instantiable': + return instantiableCloudDeviceRepository.create(data) + case 'device': + return concreteDeviceRepository.create(data) + case 'edge instantiable': + return instantiableBrowserDeviceRepository.create(data) + case 'group': + return deviceGroupRepository.create(data) + } + } + + async write(model: DeviceModel, data: DeviceUpdate<'request'>): Promise { switch (model.type) { case 'cloud instantiable': - if (!isInstantiableCloudDevice(data)) { - throw new InvalidValueError( - `Provided data cannot be used to update the given device`, - 400 - ) - } return await instantiableCloudDeviceRepository.write(model, data) case 'device': - if (!isConcreteDevice(data)) { - throw new InvalidValueError( - `Provided data cannot be used to update the given device`, - 400 - ) - } return await concreteDeviceRepository.write(model, data) case 'edge instantiable': - if (!isInstantiableBrowserDevice(data)) { - throw new InvalidValueError( - `Provided data cannot be used to update the given device`, - 400 - ) - } return await instantiableBrowserDeviceRepository.write(model, data) case 'group': - if (!isDeviceGroup(data)) { - throw new InvalidValueError( - `Provided data cannot be used to update the given device`, - 400 - ) - } return await deviceGroupRepository.write(model, data) } } async format( model: DeviceModel, - options?: { flatGroup?: boolean } + options?: { flatGroup?: boolean; overview?: boolean } ): Promise> { + if (options?.overview) return await DeviceOverviewRepository.format(model) + switch (model.type) { case 'cloud instantiable': return await instantiableCloudDeviceRepository.format(model) @@ -83,10 +69,6 @@ export class DeviceRepository extends AbstractRepository< return await deviceGroupRepository.format(model, options?.flatGroup) } } - - async formatOverview(model: DeviceModel): Promise> { - return await DeviceOverviewRepository.format(model) - } } export const deviceRepository = new DeviceRepository() diff --git a/services/device/src/database/repositories/device/concreteDevice.ts b/services/device/src/database/repositories/device/concreteDevice.ts index 48b8c58b..1f82397b 100644 --- a/services/device/src/database/repositories/device/concreteDevice.ts +++ b/services/device/src/database/repositories/device/concreteDevice.ts @@ -1,4 +1,8 @@ -import { ConcreteDevice } from '../../../generated/types' +import { + ConcreteDevice, + ConcreteDeviceInit, + ConcreteDeviceUpdate, +} from '../../../generated/types' import { ConcreteDeviceModel } from '../../model' import { DeviceOverviewRepository } from './deviceOverview' import { @@ -19,9 +23,15 @@ export class ConcreteDeviceRepository extends AbstractRepository< this.repository = AppDataSource.getRepository(ConcreteDeviceModel) } + async create(data?: ConcreteDeviceInit<'request'>): Promise { + const model = await super.create(data) + model.type = 'device' + return model + } + async write( model: ConcreteDeviceModel, - data: ConcreteDevice<'request'> + data: ConcreteDeviceUpdate<'request'> ): Promise { await DeviceOverviewRepository.write(model, data) diff --git a/services/device/src/database/repositories/device/deviceGroup.ts b/services/device/src/database/repositories/device/deviceGroup.ts index d799f9dc..7ccaae2c 100644 --- a/services/device/src/database/repositories/device/deviceGroup.ts +++ b/services/device/src/database/repositories/device/deviceGroup.ts @@ -1,4 +1,10 @@ -import { Device, DeviceGroup, DeviceReference } from '../../../generated/types' +import { + Device, + DeviceGroup, + DeviceGroupInit, + DeviceGroupUpdate, + DeviceReference, +} from '../../../generated/types' import { apiClient } from '../../../globals' import { DeviceGroupModel } from '../../model' import { DeviceOverviewRepository } from './deviceOverview' @@ -20,7 +26,16 @@ export class DeviceGroupRepository extends AbstractRepository< this.repository = AppDataSource.getRepository(DeviceGroupModel) } - async write(model: DeviceGroupModel, data: DeviceGroup<'request'>): Promise { + async create(data?: DeviceGroupInit<'request'>): Promise { + const model = await super.create(data) + model.type = 'group' + return model + } + + async write( + model: DeviceGroupModel, + data: DeviceGroupUpdate<'request'> + ): Promise { await DeviceOverviewRepository.write(model, data) model.devices = data.devices @@ -54,7 +69,9 @@ export class DeviceGroupRepository extends AbstractRepository< if (!device) continue if (device.type === 'group' && flatGroup) { - devices.push(...(device.devices ?? [])) + devices.push( + ...(await this.resolveDeviceReferences(device.devices ?? [])) + ) } else { devices.push(device) } diff --git a/services/device/src/database/repositories/device/deviceOverview.ts b/services/device/src/database/repositories/device/deviceOverview.ts index 72ad4ee4..58858444 100644 --- a/services/device/src/database/repositories/device/deviceOverview.ts +++ b/services/device/src/database/repositories/device/deviceOverview.ts @@ -1,4 +1,4 @@ -import { DeviceOverview } from '../../../generated/types' +import { DeviceOverview, DeviceOverviewUpdate } from '../../../generated/types' import { deviceUrlFromId } from '../../../methods/urlFromId' import { DeviceOverviewModel } from '../../model' import { AbstractRepository } from '@crosslab/service-common' @@ -10,11 +10,10 @@ export abstract class DeviceOverviewRepository extends AbstractRepository< > { static async write( model: DeviceOverviewModel, - data: DeviceOverview<'request'> + data: DeviceOverviewUpdate<'request'> ): Promise { if (data.name) model.name = data.name if (data.description) model.description = data.description - if (data.type) model.type = data.type } static async format(model: DeviceOverviewModel): Promise> { diff --git a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts index 00215433..00a1ef35 100644 --- a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts +++ b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts @@ -1,4 +1,8 @@ -import { InstantiableBrowserDevice } from '../../../generated/types' +import { + InstantiableBrowserDevice, + InstantiableBrowserDeviceInit, + InstantiableBrowserDeviceUpdate, +} from '../../../generated/types' import { InstantiableBrowserDeviceModel } from '../../model' import { DeviceOverviewRepository } from './deviceOverview' import { @@ -19,9 +23,17 @@ export class InstantiableBrowserDeviceRepository extends AbstractRepository< this.repository = AppDataSource.getRepository(InstantiableBrowserDeviceModel) } + async create( + data?: InstantiableBrowserDeviceInit<'request'> + ): Promise { + const model = await super.create(data) + model.type = 'edge instantiable' + return model + } + async write( model: InstantiableBrowserDeviceModel, - data: InstantiableBrowserDevice<'request'> + data: InstantiableBrowserDeviceUpdate<'request'> ) { await DeviceOverviewRepository.write(model, data) diff --git a/services/device/src/database/repositories/device/instantiableCloudDevice.ts b/services/device/src/database/repositories/device/instantiableCloudDevice.ts index bda1e772..a5282af9 100644 --- a/services/device/src/database/repositories/device/instantiableCloudDevice.ts +++ b/services/device/src/database/repositories/device/instantiableCloudDevice.ts @@ -1,4 +1,8 @@ -import { InstantiableCloudDevice } from '../../../generated/types' +import { + InstantiableCloudDevice, + InstantiableCloudDeviceInit, + InstantiableCloudDeviceUpdate, +} from '../../../generated/types' import { InstantiableCloudDeviceModel } from '../../model' import { DeviceOverviewRepository } from './deviceOverview' import { @@ -19,9 +23,17 @@ export class InstantiableCloudDeviceRepository extends AbstractRepository< this.repository = AppDataSource.getRepository(InstantiableCloudDeviceModel) } + async create( + data?: InstantiableCloudDeviceInit<'request'> + ): Promise { + const model = await super.create(data) + model.type = 'cloud instantiable' + return model + } + async write( model: InstantiableCloudDeviceModel, - data: InstantiableCloudDevice<'request'> + data: InstantiableCloudDeviceUpdate<'request'> ) { await DeviceOverviewRepository.write(model, data) diff --git a/services/device/src/operations/devices/get.ts b/services/device/src/operations/devices/get.ts index 6bdf4744..64da1d00 100644 --- a/services/device/src/operations/devices/get.ts +++ b/services/device/src/operations/devices/get.ts @@ -13,6 +13,8 @@ export const getDevices: getDevicesSignature = async (_user) => { return { status: 200, - body: await Promise.all(devices.map(deviceRepository.formatOverview)), + body: await Promise.all( + devices.map((device) => deviceRepository.format(device, { overview: true })) + ), } } diff --git a/services/device/test/data/devices/concrete_device.spec.ts b/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts similarity index 80% rename from services/device/test/data/devices/concrete_device.spec.ts rename to services/device/test/data/devices/concreteDevices/concrete_device.spec.ts index f4c3b407..b9c42748 100644 --- a/services/device/test/data/devices/concrete_device.spec.ts +++ b/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts @@ -1,4 +1,4 @@ -import { DeviceRepository } from '../../../src/database/repositories/device' +import { ConcreteDeviceRepository } from '../../../../src/database/repositories/device/concreteDevice' import { EntityData } from '@crosslab/service-common' const uuid = '32348c89-f302-408f-8582-cb9783c74fbb' @@ -7,7 +7,7 @@ const name = 'Concrete Device Example' const description = 'An example for a concrete device' const owner = 'http://localhost/users/superadmin' -const concrete_device: EntityData = { +const concrete_device: EntityData = { request: { type, name, diff --git a/services/device/test/data/devices/concreteDevices/index.spec.ts b/services/device/test/data/devices/concreteDevices/index.spec.ts new file mode 100644 index 00000000..7ecce303 --- /dev/null +++ b/services/device/test/data/devices/concreteDevices/index.spec.ts @@ -0,0 +1,14 @@ +import { ConcreteDeviceRepository } from '../../../../src/database/repositories/device/concreteDevice' +import concrete_device from './concrete_device.spec' +import { EntityData } from '@crosslab/service-common' + +export const concreteDeviceNames = ['concrete device'] as const +export type ConcreteDeviceName = (typeof concreteDeviceNames)[number] +export type ConcreteDeviceData = Record< + ConcreteDeviceName, + EntityData +> + +export const concreteDeviceData: ConcreteDeviceData = { + 'concrete device': concrete_device, +} diff --git a/services/device/test/data/devices/deviceGroups/device_group.spec.ts b/services/device/test/data/devices/deviceGroups/device_group.spec.ts new file mode 100644 index 00000000..5da31e90 --- /dev/null +++ b/services/device/test/data/devices/deviceGroups/device_group.spec.ts @@ -0,0 +1,36 @@ +import { DeviceGroupRepository } from '../../../../src/database/repositories/device/deviceGroup' +import { EntityData } from '@crosslab/service-common' + +const uuid = 'd65b289a-44c5-452f-8c7b-e003714d3645' +const type = 'group' +const name = 'Device Group Example' +const description = 'An example for a device group' +const owner = 'http://localhost/users/superadmin' +const devices = [{ url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb' }] + +const device_group: EntityData = { + request: { + type, + name, + description, + devices, + }, + model: { + uuid, + type, + name, + description, + devices, + owner, + }, + response: { + url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', + type, + name, + description, + devices, + owner, + }, +} + +export default device_group diff --git a/services/device/test/data/devices/deviceGroups/index.spec.ts b/services/device/test/data/devices/deviceGroups/index.spec.ts new file mode 100644 index 00000000..ab7be5fa --- /dev/null +++ b/services/device/test/data/devices/deviceGroups/index.spec.ts @@ -0,0 +1,11 @@ +import { DeviceGroupRepository } from '../../../../src/database/repositories/device/deviceGroup' +import device_group from './device_group.spec' +import { EntityData } from '@crosslab/service-common' + +export const deviceGroupNames = ['device group'] as const +export type DeviceGroupName = (typeof deviceGroupNames)[number] +export type DeviceGroupData = Record> + +export const deviceGroupData: DeviceGroupData = { + 'device group': { ...device_group }, +} diff --git a/services/device/test/data/devices/index.spec.ts b/services/device/test/data/devices/index.spec.ts index a156cc76..e8e315d7 100644 --- a/services/device/test/data/devices/index.spec.ts +++ b/services/device/test/data/devices/index.spec.ts @@ -1,11 +1,41 @@ import { DeviceRepository } from '../../../src/database/repositories/device' -import concrete_device from './concrete_device.spec' +import { concreteDeviceData, ConcreteDeviceName } from './concreteDevices/index.spec' +import { concreteDeviceNames } from './concreteDevices/index.spec' +import { + deviceGroupData, + DeviceGroupName, + deviceGroupNames, +} from './deviceGroups/index.spec' +import { + instantiableBrowserDeviceData, + InstantiableBrowserDeviceName, + instantiableBrowserDeviceNames, +} from './instantiableBrowserDevices/index.spec' +import { + instantiableCloudDeviceData, + InstantiableCloudDeviceName, + instantiableCloudDeviceNames, +} from './instantiableCloudDevices/index.spec' import { EntityData } from '@crosslab/service-common' -export const deviceNames = ['concrete device'] as const +export const deviceNames = [ + ...concreteDeviceNames, + ...deviceGroupNames, + ...instantiableBrowserDeviceNames, + ...instantiableCloudDeviceNames, +] as const export type DeviceName = (typeof deviceNames)[number] export type DeviceData = Record> export const deviceData: DeviceData = { - 'concrete device': concrete_device, + ...(concreteDeviceData as Record>), + ...(deviceGroupData as Record>), + ...(instantiableBrowserDeviceData as Record< + InstantiableBrowserDeviceName, + EntityData + >), + ...(instantiableCloudDeviceData as Record< + InstantiableCloudDeviceName, + EntityData + >), } diff --git a/services/device/test/data/devices/instantiableBrowserDevices/index.spec.ts b/services/device/test/data/devices/instantiableBrowserDevices/index.spec.ts new file mode 100644 index 00000000..9f1d8215 --- /dev/null +++ b/services/device/test/data/devices/instantiableBrowserDevices/index.spec.ts @@ -0,0 +1,15 @@ +import { InstantiableBrowserDeviceRepository } from '../../../../src/database/repositories/device/instantiableBrowserDevice' +import instantiable_browser_device from './instantiable_browser_device.spec' +import { EntityData } from '@crosslab/service-common' + +export const instantiableBrowserDeviceNames = ['instantiable browser device'] as const +export type InstantiableBrowserDeviceName = + (typeof instantiableBrowserDeviceNames)[number] +export type InstantiableBrowserDeviceData = Record< + InstantiableBrowserDeviceName, + EntityData +> + +export const instantiableBrowserDeviceData: InstantiableBrowserDeviceData = { + 'instantiable browser device': { ...instantiable_browser_device }, +} diff --git a/services/device/test/data/devices/instantiableBrowserDevices/instantiable_browser_device.spec.ts b/services/device/test/data/devices/instantiableBrowserDevices/instantiable_browser_device.spec.ts new file mode 100644 index 00000000..8f32f2b6 --- /dev/null +++ b/services/device/test/data/devices/instantiableBrowserDevices/instantiable_browser_device.spec.ts @@ -0,0 +1,36 @@ +import { InstantiableBrowserDeviceRepository } from '../../../../src/database/repositories/device/instantiableBrowserDevice' +import { EntityData } from '@crosslab/service-common' + +const uuid = '3742d2bd-8259-4dba-8908-f54dba68ba69' +const type = 'edge instantiable' +const name = 'Instantiable Browser Device Example' +const description = 'An example for an instantiable browser device' +const owner = 'http://localhost/users/superadmin' +const codeUrl = 'http://localhost/code' + +const instantiable_browser_device: EntityData = { + request: { + type, + name, + description, + codeUrl, + }, + model: { + uuid, + type, + name, + description, + owner, + codeUrl, + }, + response: { + url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', + type, + name, + description, + owner, + codeUrl, + }, +} + +export default instantiable_browser_device diff --git a/services/device/test/data/devices/instantiableCloudDevices/index.spec.ts b/services/device/test/data/devices/instantiableCloudDevices/index.spec.ts new file mode 100644 index 00000000..66d64a6b --- /dev/null +++ b/services/device/test/data/devices/instantiableCloudDevices/index.spec.ts @@ -0,0 +1,14 @@ +import { InstantiableCloudDeviceRepository } from '../../../../src/database/repositories/device/instantiableCloudDevice' +import instantiable_cloud_device from './instantiable_cloud_device.spec' +import { EntityData } from '@crosslab/service-common' + +export const instantiableCloudDeviceNames = ['instantiable cloud device'] as const +export type InstantiableCloudDeviceName = (typeof instantiableCloudDeviceNames)[number] +export type InstantiableCloudDeviceData = Record< + InstantiableCloudDeviceName, + EntityData +> + +export const instantiableCloudDeviceData: InstantiableCloudDeviceData = { + 'instantiable cloud device': { ...instantiable_cloud_device }, +} diff --git a/services/device/test/data/devices/instantiableCloudDevices/instantiable_cloud_device.spec.ts b/services/device/test/data/devices/instantiableCloudDevices/instantiable_cloud_device.spec.ts new file mode 100644 index 00000000..73c7d8c3 --- /dev/null +++ b/services/device/test/data/devices/instantiableCloudDevices/instantiable_cloud_device.spec.ts @@ -0,0 +1,36 @@ +import { InstantiableCloudDeviceRepository } from '../../../../src/database/repositories/device/instantiableCloudDevice' +import { EntityData } from '@crosslab/service-common' + +const uuid = '15d9de70-3646-4d05-a83b-3c70862c0b98' +const type = 'cloud instantiable' +const name = 'Instantiable Cloud Device Example' +const description = 'An example for an instantiable cloud device' +const owner = 'http://localhost/users/superadmin' +const instantiateUrl = 'http://localhost/code' + +const instantiable_cloud_device: EntityData = { + request: { + type, + name, + description, + instantiateUrl, + }, + model: { + uuid, + type, + name, + description, + owner, + instantiateUrl, + }, + response: { + url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', + type, + name, + description, + owner, + instantiateUrl, + }, +} + +export default instantiable_cloud_device diff --git a/services/device/test/data/index.spec.ts b/services/device/test/data/index.spec.ts index bb0920e1..101026b0 100644 --- a/services/device/test/data/index.spec.ts +++ b/services/device/test/data/index.spec.ts @@ -1,11 +1,40 @@ import { DeviceRepository } from '../../src/database/repositories/device' +import { ConcreteDeviceRepository } from '../../src/database/repositories/device/concreteDevice' +import { DeviceGroupRepository } from '../../src/database/repositories/device/deviceGroup' +import { InstantiableBrowserDeviceRepository } from '../../src/database/repositories/device/instantiableBrowserDevice' +import { InstantiableCloudDeviceRepository } from '../../src/database/repositories/device/instantiableCloudDevice' import { PeerconnectionRepository } from '../../src/database/repositories/peerconnection' +import { + concreteDeviceData, + ConcreteDeviceName, +} from './devices/concreteDevices/index.spec' +import { deviceGroupData, DeviceGroupName } from './devices/deviceGroups/index.spec' import { deviceData, DeviceName } from './devices/index.spec' +import { + instantiableBrowserDeviceData, + InstantiableBrowserDeviceName, +} from './devices/instantiableBrowserDevices/index.spec' +import { + instantiableCloudDeviceData, + InstantiableCloudDeviceName, +} from './devices/instantiableCloudDevices/index.spec' import { peerconnectionData, PeerconnectionName } from './peerconnections/index.spec' import { GenericTestData } from '@crosslab/service-common' export type TestData = GenericTestData< [ + ['concrete devices', ConcreteDeviceName, ConcreteDeviceRepository], + ['device groups', DeviceGroupName, DeviceGroupRepository], + [ + 'instantiable browser devices', + InstantiableBrowserDeviceName, + InstantiableBrowserDeviceRepository + ], + [ + 'instantiable cloud devices', + InstantiableCloudDeviceName, + InstantiableCloudDeviceRepository + ], ['devices', DeviceName, DeviceRepository], ['peerconnections', PeerconnectionName, PeerconnectionRepository] ] @@ -13,7 +42,11 @@ export type TestData = GenericTestData< export function prepareTestData(): TestData { return { - devices: deviceData, - peerconnections: peerconnectionData, + 'concrete devices': concreteDeviceData, + 'device groups': deviceGroupData, + 'instantiable browser devices': instantiableBrowserDeviceData, + 'instantiable cloud devices': instantiableCloudDeviceData, + 'devices': deviceData, + 'peerconnections': peerconnectionData, } } diff --git a/services/device/test/database/index.spec.ts b/services/device/test/database/index.spec.ts index e69de29b..262f1aa9 100644 --- a/services/device/test/database/index.spec.ts +++ b/services/device/test/database/index.spec.ts @@ -0,0 +1,16 @@ +import repositorySuite from './repositories/index.spec' + +const tests = [repositorySuite] + +describe('Database', function () { + this.beforeAll(function () { + console.log = (_message: any, ..._optionalParams: any[]) => undefined + console.error = (_message: any, ..._optionalParams: any[]) => undefined + console.warn = (_message: any, ..._optionalParams: any[]) => undefined + console.info = (_message: any, ..._optionalParams: any[]) => undefined + }) + + for (const test of tests) { + test() + } +}) diff --git a/services/device/test/database/repositories/device.spec.ts b/services/device/test/database/repositories/device.spec.ts index cef051fc..587a9437 100644 --- a/services/device/test/database/repositories/device.spec.ts +++ b/services/device/test/database/repositories/device.spec.ts @@ -4,11 +4,16 @@ import { deviceRepository, DeviceRepository, } from '../../../src/database/repositories/device' -import { Device, DeviceInit } from '../../../src/generated/types' -import { DeviceName } from '../../data/device.spec' +import { Device, DeviceInit, DeviceUpdate } from '../../../src/generated/types' +import { deviceData, DeviceName, deviceNames } from '../../data/devices/index.spec' +import { concreteDeviceRepositoryTestSuite } from './device/concreteDevice.spec' +import { deviceGroupRepositoryTestSuite } from './device/deviceGroup.spec' +import { instantiableBrowserDeviceRepositoryTestSuite } from './device/instantiableBrowserDevice.spec' +import { instantiableCloudDeviceRepositoryTestSuite } from './device/instantiableCloudDevice.spec' import { initTestDatabase } from './index.spec' import { AbstractRepositoryTestSuite } from '@crosslab/service-common' import assert from 'assert' +import Mocha from 'mocha' import { FindOptionsWhere } from 'typeorm' class DeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< @@ -24,66 +29,181 @@ class DeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< super(AppDataSource) } + public async initialize(): Promise { + await super.initialize() + if (!this.testSuites) throw new Error('Test suites have not been initialized!') + + this.removeSuite('write') + this.addSuite('write', (data) => { + const testSuite = new Mocha.Suite('write') + + for (const key of deviceNames) { + testSuite.addTest( + new Mocha.Test( + `should write valid data to a model correctly (${key})`, + async function () { + const model = await data.repository.create({ + type: deviceData[key].request.type, + }) + assert(data.validateCreate(model)) + await data.repository.write( + model, + data.entityData[key].request + ) + assert( + data.validateWrite(model, data.entityData[key].request) + ) + } + ) + ) + } + + return testSuite + }) + } + validateCreate( model: DeviceModel, data?: DeviceInit<'request'> | undefined ): boolean { - if (!data) { - return true - } - - if (data?.name) assert(model.name === data.name) - if (data?.description) assert(model.description === data.description) + if (!data) return true switch (model.type) { case 'cloud instantiable': - assert(model.type === data.type) - if (data.instantiateUrl) - assert(model.instantiateUrl === data.instantiateUrl) - if (data.services) assert(model.services === data.services) - break + assert(data?.type === model.type) + return instantiableCloudDeviceRepositoryTestSuite.validateCreate( + model, + data + ) case 'device': - assert(model.type === data.type) - if (data.services) assert(model.services === data.services) - break + assert(data?.type === model.type) + return concreteDeviceRepositoryTestSuite.validateCreate(model, data) case 'edge instantiable': - assert(model.type === data.type) - if (data.codeUrl) assert(model.codeUrl === data.codeUrl) - if (data.services) assert(model.services === data.services) - break + assert(data?.type === model.type) + return instantiableBrowserDeviceRepositoryTestSuite.validateCreate( + model, + data + ) case 'group': - assert(model.type === data.type) - if (data.devices) { - for (const device of data.devices) { - assert(model.devices?.find((d) => d.url === device.url)) - } - for (const device of model.devices ?? []) { - assert(data.devices.find((d) => d.url === device.url)) - } - } - break + assert(data?.type === model.type) + return deviceGroupRepositoryTestSuite.validateCreate(model, data) } - - return true } - validateWrite(model: DeviceModel, data: Device<'request'>): boolean { - throw new Error('Method not implemented.') + + validateWrite(model: DeviceModel, data: DeviceUpdate<'request'>): boolean { + switch (model.type) { + case 'cloud instantiable': + assert(data?.type === model.type) + return instantiableCloudDeviceRepositoryTestSuite.validateWrite( + model, + data + ) + case 'device': + assert(data?.type === model.type) + return concreteDeviceRepositoryTestSuite.validateWrite(model, data) + case 'edge instantiable': + assert(data?.type === model.type) + return instantiableBrowserDeviceRepositoryTestSuite.validateWrite( + model, + data + ) + case 'group': + assert(data?.type === model.type) + return deviceGroupRepositoryTestSuite.validateWrite(model, data) + } } + validateFormat(model: DeviceModel, data: Device<'response'>): boolean { - throw new Error('Method not implemented.') + switch (model.type) { + case 'cloud instantiable': + assert(data?.type === model.type) + return instantiableCloudDeviceRepositoryTestSuite.validateFormat( + model, + data + ) + case 'device': + assert(data?.type === model.type) + return concreteDeviceRepositoryTestSuite.validateFormat(model, data) + case 'edge instantiable': + assert(data?.type === model.type) + return instantiableBrowserDeviceRepositoryTestSuite.validateFormat( + model, + data + ) + case 'group': + assert(data?.type === model.type) + return deviceGroupRepositoryTestSuite.validateFormat(model, data) + } } + compareModels( firstModel: DeviceModel, secondModel: DeviceModel, - complete?: boolean | undefined + complete?: boolean ): boolean { - throw new Error('Method not implemented.') + const sameId = firstModel.uuid === secondModel.uuid + + if (!complete) return sameId + + switch (firstModel.type) { + case 'cloud instantiable': + assert(firstModel.type === secondModel.type) + return instantiableCloudDeviceRepositoryTestSuite.compareModels( + firstModel, + secondModel + ) + case 'device': + assert(firstModel.type === secondModel.type) + return concreteDeviceRepositoryTestSuite.compareModels( + firstModel, + secondModel + ) + case 'edge instantiable': + assert(firstModel.type === secondModel.type) + return instantiableBrowserDeviceRepositoryTestSuite.compareModels( + firstModel, + secondModel + ) + case 'group': + assert(firstModel.type === secondModel.type) + return deviceGroupRepositoryTestSuite.compareModels( + firstModel, + secondModel + ) + } } + compareFormatted(first: Device<'response'>, second: Device<'response'>): boolean { - throw new Error('Method not implemented.') + switch (first.type) { + case 'cloud instantiable': + assert(first.type === second.type) + return instantiableCloudDeviceRepositoryTestSuite.compareFormatted( + first, + second + ) + case 'device': + assert(first.type === second.type) + return concreteDeviceRepositoryTestSuite.compareFormatted(first, second) + case 'edge instantiable': + assert(first.type === second.type) + return instantiableBrowserDeviceRepositoryTestSuite.compareFormatted( + first, + second + ) + case 'group': + assert(first.type === second.type) + return deviceGroupRepositoryTestSuite.compareFormatted(first, second) + } } - getFindOptionsWhere(model?: DeviceModel | undefined): FindOptionsWhere { - throw new Error('Method not implemented.') + + getFindOptionsWhere(model?: DeviceModel): FindOptionsWhere { + return model + ? { + uuid: model?.uuid, + } + : { + uuid: '', + } } } diff --git a/services/device/test/database/repositories/device/concreteDevice.spec.ts b/services/device/test/database/repositories/device/concreteDevice.spec.ts new file mode 100644 index 00000000..2b04a788 --- /dev/null +++ b/services/device/test/database/repositories/device/concreteDevice.spec.ts @@ -0,0 +1,130 @@ +import { AppDataSource } from '../../../../src/database/dataSource' +import { ConcreteDeviceModel } from '../../../../src/database/model' +import { + concreteDeviceRepository, + ConcreteDeviceRepository, +} from '../../../../src/database/repositories/device/concreteDevice' +import { + ConcreteDevice, + ConcreteDeviceInit, + ConcreteDeviceUpdate, +} from '../../../../src/generated/types' +import { ConcreteDeviceName } from '../../../data/devices/concreteDevices/index.spec' +import { initTestDatabase } from '../index.spec' +import { DeviceOverviewRepositoryTestSuite } from './deviceOverview.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import { FindOptionsWhere } from 'typeorm' + +class ConcreteDeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< + ConcreteDeviceName, + ConcreteDeviceRepository +> { + protected name = 'concrete devices' as const + protected repository = concreteDeviceRepository + protected getEntityData = async () => (await initTestDatabase())['concrete devices'] + protected RepositoryClass = ConcreteDeviceRepository + + constructor() { + super(AppDataSource) + } + + validateCreate( + model: ConcreteDeviceModel, + data?: ConcreteDeviceInit<'request'> + ): boolean { + if (!data) return true + + assert(DeviceOverviewRepositoryTestSuite.validateCreate(model, data)) + assert(this.validateWrite(model, data)) + + return true + } + + validateWrite( + model: ConcreteDeviceModel, + data: ConcreteDeviceUpdate<'request'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.validateWrite(model, data)) + if (data.experiment) assert(model.experiment === data.experiment) + if (data.services) + assert(JSON.stringify(model.services) === JSON.stringify(data.services)) + + return true + } + + validateFormat( + model: ConcreteDeviceModel, + data: ConcreteDevice<'response'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) + assert( + JSON.stringify(data.announcedAvailability) === + JSON.stringify(model.announcedAvailability) + ) + assert(data.connected === model.connected) + assert(data.experiment === model.experiment) + assert(JSON.stringify(data.services) === JSON.stringify(model.services)) + + return true + } + + compareModels( + firstModel: ConcreteDeviceModel, + secondModel: ConcreteDeviceModel, + complete?: boolean + ): boolean { + const sameId = firstModel.uuid === secondModel.uuid + + if (!complete) return sameId + + assert(DeviceOverviewRepositoryTestSuite.compareModels(firstModel, secondModel)) + assert( + JSON.stringify(firstModel.announcedAvailability) === + JSON.stringify(secondModel.announcedAvailability) + ) + assert( + JSON.stringify(firstModel.availabilityRules) === + JSON.stringify(secondModel.availabilityRules) + ) + assert(firstModel.connected === secondModel.connected) + assert(firstModel.experiment === secondModel.experiment) + assert(firstModel.instanceOf?.uuid === secondModel.instanceOf?.uuid) + assert( + JSON.stringify(firstModel.services) === JSON.stringify(secondModel.services) + ) + assert(firstModel.token === secondModel.token) + + return true + } + + compareFormatted( + first: ConcreteDevice<'response'>, + second: ConcreteDevice<'response'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.compareFormatted(first, second)) + assert( + JSON.stringify(first.announcedAvailability) === + JSON.stringify(second.announcedAvailability) + ) + assert(first.connected === second.connected) + assert(first.experiment === second.experiment) + assert(JSON.stringify(first.services) === JSON.stringify(second.services)) + + return true + } + + getFindOptionsWhere( + model?: ConcreteDeviceModel + ): FindOptionsWhere { + return model + ? { + uuid: model?.uuid, + } + : { + uuid: '', + } + } +} + +export const concreteDeviceRepositoryTestSuite = new ConcreteDeviceRepositoryTestSuite() diff --git a/services/device/test/database/repositories/device/deviceGroup.spec.ts b/services/device/test/database/repositories/device/deviceGroup.spec.ts new file mode 100644 index 00000000..3ede0a71 --- /dev/null +++ b/services/device/test/database/repositories/device/deviceGroup.spec.ts @@ -0,0 +1,95 @@ +import { AppDataSource } from '../../../../src/database/dataSource' +import { DeviceGroupModel } from '../../../../src/database/model' +import { + deviceGroupRepository, + DeviceGroupRepository, +} from '../../../../src/database/repositories/device/deviceGroup' +import { + DeviceGroup, + DeviceGroupInit, + DeviceGroupUpdate, +} from '../../../../src/generated/types' +import { DeviceGroupName } from '../../../data/devices/deviceGroups/index.spec' +import { initTestDatabase } from '../index.spec' +import { DeviceOverviewRepositoryTestSuite } from './deviceOverview.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import { FindOptionsWhere } from 'typeorm' + +class DeviceGroupRepositoryTestSuite extends AbstractRepositoryTestSuite< + DeviceGroupName, + DeviceGroupRepository +> { + protected name = 'concrete devices' as const + protected repository = deviceGroupRepository + protected getEntityData = async () => (await initTestDatabase())['device groups'] + protected RepositoryClass = DeviceGroupRepository + + constructor() { + super(AppDataSource) + } + + validateCreate(model: DeviceGroupModel, data?: DeviceGroupInit<'request'>): boolean { + if (!data) return true + + assert(DeviceOverviewRepositoryTestSuite.validateCreate(model, data)) + assert(this.validateWrite(model, data)) + + return true + } + + validateWrite(model: DeviceGroupModel, data: DeviceGroupUpdate<'request'>): boolean { + assert(DeviceOverviewRepositoryTestSuite.validateWrite(model, data)) + if (data.devices) + assert( + JSON.stringify(model.devices) === JSON.stringify(data.devices), + 'Contained devices differ' + ) + + return true + } + + validateFormat(model: DeviceGroupModel, data: DeviceGroup<'response'>): boolean { + assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) + assert(JSON.stringify(data.devices) === JSON.stringify(model.devices)) // TODO + + return true + } + + compareModels( + firstModel: DeviceGroupModel, + secondModel: DeviceGroupModel, + complete?: boolean + ): boolean { + const sameId = firstModel.uuid === secondModel.uuid + + if (!complete) return sameId + + assert(DeviceOverviewRepositoryTestSuite.compareModels(firstModel, secondModel)) + assert(JSON.stringify(firstModel.devices) === JSON.stringify(secondModel.devices)) + + return true + } + + compareFormatted( + first: DeviceGroup<'response'>, + second: DeviceGroup<'response'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.compareFormatted(first, second)) + assert(JSON.stringify(first.devices) === JSON.stringify(second.devices)) + + return true + } + + getFindOptionsWhere(model?: DeviceGroupModel): FindOptionsWhere { + return model + ? { + uuid: model?.uuid, + } + : { + uuid: '', + } + } +} + +export const deviceGroupRepositoryTestSuite = new DeviceGroupRepositoryTestSuite() diff --git a/services/device/test/database/repositories/device/deviceOverview.spec.ts b/services/device/test/database/repositories/device/deviceOverview.spec.ts new file mode 100644 index 00000000..fff6a281 --- /dev/null +++ b/services/device/test/database/repositories/device/deviceOverview.spec.ts @@ -0,0 +1,82 @@ +import { DeviceOverviewModel } from '../../../../src/database/model' +import { DeviceOverviewRepository } from '../../../../src/database/repositories/device/deviceOverview' +import { + DeviceInit, + DeviceOverview, + DeviceOverviewUpdate, +} from '../../../../src/generated/types' +import { deviceUrlFromId } from '../../../../src/methods/urlFromId' +import { DeviceName } from '../../../data/devices/index.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' + +export abstract class DeviceOverviewRepositoryTestSuite extends AbstractRepositoryTestSuite< + DeviceName, + DeviceOverviewRepository +> { + static validateCreate( + model: DeviceOverviewModel, + data?: DeviceInit<'request'> + ): boolean { + if (!data) return true + + assert(model.type === data.type) + assert(this.validateWrite(model, data)) + + return true + } + + static validateWrite( + model: DeviceOverviewModel, + data: DeviceOverviewUpdate<'request'> + ): boolean { + if (data.name) assert(model.name === data.name) + if (data.description) assert(model.description === data.description) + + return true + } + + static validateFormat( + model: DeviceOverviewModel, + data: DeviceOverview<'response'> + ): boolean { + assert(data.description === model.description) + assert(data.name === model.name) + assert(data.owner === model.owner) + assert(data.type === model.type) + assert(data.url === deviceUrlFromId(model.uuid)) + + return true + } + + static compareModels( + firstModel: DeviceOverviewModel, + secondModel: DeviceOverviewModel, + complete?: boolean + ): boolean { + const sameId = firstModel.uuid === secondModel.uuid + + if (!complete) return sameId + + assert(firstModel.deletedAt === secondModel.deletedAt) + assert(firstModel.description === secondModel.description) + assert(firstModel.name === secondModel.name) + assert(firstModel.owner === secondModel.owner) + assert(firstModel.type === secondModel.type) + + return true + } + + static compareFormatted( + first: DeviceOverview<'response'>, + second: DeviceOverview<'response'> + ): boolean { + assert(first.description === second.description) + assert(first.name === second.name) + assert(first.owner === second.owner) + assert(first.type === second.type) + assert(first.url === second.url) + + return true + } +} diff --git a/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts b/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts new file mode 100644 index 00000000..25baafd0 --- /dev/null +++ b/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts @@ -0,0 +1,114 @@ +import { AppDataSource } from '../../../../src/database/dataSource' +import { InstantiableBrowserDeviceModel } from '../../../../src/database/model' +import { + instantiableBrowserDeviceRepository, + InstantiableBrowserDeviceRepository, +} from '../../../../src/database/repositories/device/instantiableBrowserDevice' +import { + InstantiableBrowserDevice, + InstantiableBrowserDeviceInit, + InstantiableBrowserDeviceUpdate, +} from '../../../../src/generated/types' +import { InstantiableBrowserDeviceName } from '../../../data/devices/instantiableBrowserDevices/index.spec' +import { initTestDatabase } from '../index.spec' +import { DeviceOverviewRepositoryTestSuite } from './deviceOverview.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import { FindOptionsWhere } from 'typeorm' + +class InstantiableBrowserDeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< + InstantiableBrowserDeviceName, + InstantiableBrowserDeviceRepository +> { + protected name = 'concrete devices' as const + protected repository = instantiableBrowserDeviceRepository + protected getEntityData = async () => + (await initTestDatabase())['instantiable browser devices'] + protected RepositoryClass = InstantiableBrowserDeviceRepository + + constructor() { + super(AppDataSource) + } + + validateCreate( + model: InstantiableBrowserDeviceModel, + data?: InstantiableBrowserDeviceInit<'request'> + ): boolean { + if (!data) return true + + assert(DeviceOverviewRepositoryTestSuite.validateCreate(model, data)) + assert(this.validateWrite(model, data)) + + return true + } + + validateWrite( + model: InstantiableBrowserDeviceModel, + data: InstantiableBrowserDeviceUpdate<'request'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.validateWrite(model, data)) + if (data.codeUrl) assert(model.codeUrl === data.codeUrl) + if (data.services) + assert(JSON.stringify(model.services) === JSON.stringify(data.services)) + + return true + } + + validateFormat( + model: InstantiableBrowserDeviceModel, + data: InstantiableBrowserDevice<'response'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) + assert(data.codeUrl === model.codeUrl) + assert(JSON.stringify(data.services) === JSON.stringify(model.services)) + + return true + } + + compareModels( + firstModel: InstantiableBrowserDeviceModel, + secondModel: InstantiableBrowserDeviceModel, + complete?: boolean + ): boolean { + const sameId = firstModel.uuid === secondModel.uuid + + if (!complete) return sameId + + assert(DeviceOverviewRepositoryTestSuite.compareModels(firstModel, secondModel)) + assert(firstModel.codeUrl === secondModel.codeUrl) + assert( + JSON.stringify(firstModel.instances) === JSON.stringify(secondModel.instances) + ) + assert( + JSON.stringify(firstModel.services) === JSON.stringify(secondModel.services) + ) + + return true + } + + compareFormatted( + first: InstantiableBrowserDevice<'response'>, + second: InstantiableBrowserDevice<'response'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.compareFormatted(first, second)) + assert(first.codeUrl === second.codeUrl) + assert(JSON.stringify(first.services) === JSON.stringify(second.services)) + + return true + } + + getFindOptionsWhere( + model?: InstantiableBrowserDeviceModel + ): FindOptionsWhere { + return model + ? { + uuid: model?.uuid, + } + : { + uuid: '', + } + } +} + +export const instantiableBrowserDeviceRepositoryTestSuite = + new InstantiableBrowserDeviceRepositoryTestSuite() diff --git a/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts b/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts new file mode 100644 index 00000000..aa33ced6 --- /dev/null +++ b/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts @@ -0,0 +1,114 @@ +import { AppDataSource } from '../../../../src/database/dataSource' +import { InstantiableCloudDeviceModel } from '../../../../src/database/model' +import { + instantiableCloudDeviceRepository, + InstantiableCloudDeviceRepository, +} from '../../../../src/database/repositories/device/instantiableCloudDevice' +import { + InstantiableCloudDevice, + InstantiableCloudDeviceInit, + InstantiableCloudDeviceUpdate, +} from '../../../../src/generated/types' +import { InstantiableCloudDeviceName } from '../../../data/devices/instantiableCloudDevices/index.spec' +import { initTestDatabase } from '../index.spec' +import { DeviceOverviewRepositoryTestSuite } from './deviceOverview.spec' +import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' +import { FindOptionsWhere } from 'typeorm' + +class InstantiableCloudDeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< + InstantiableCloudDeviceName, + InstantiableCloudDeviceRepository +> { + protected name = 'concrete devices' as const + protected repository = instantiableCloudDeviceRepository + protected getEntityData = async () => + (await initTestDatabase())['instantiable cloud devices'] + protected RepositoryClass = InstantiableCloudDeviceRepository + + constructor() { + super(AppDataSource) + } + + validateCreate( + model: InstantiableCloudDeviceModel, + data?: InstantiableCloudDeviceInit<'request'> + ): boolean { + if (!data) return true + + assert(DeviceOverviewRepositoryTestSuite.validateCreate(model, data)) + assert(this.validateWrite(model, data)) + + return true + } + + validateWrite( + model: InstantiableCloudDeviceModel, + data: InstantiableCloudDeviceUpdate<'request'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.validateWrite(model, data)) + if (data.codeUrl) assert(model.instantiateUrl === data.codeUrl) + if (data.services) + assert(JSON.stringify(model.services) === JSON.stringify(data.services)) + + return true + } + + validateFormat( + model: InstantiableCloudDeviceModel, + data: InstantiableCloudDevice<'response'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) + assert(data.instantiateUrl === model.instantiateUrl) + assert(JSON.stringify(data.services) === JSON.stringify(model.services)) + + return true + } + + compareModels( + firstModel: InstantiableCloudDeviceModel, + secondModel: InstantiableCloudDeviceModel, + complete?: boolean + ): boolean { + const sameId = firstModel.uuid === secondModel.uuid + + if (!complete) return sameId + + assert(DeviceOverviewRepositoryTestSuite.compareModels(firstModel, secondModel)) + assert(firstModel.instantiateUrl === secondModel.instantiateUrl) + assert( + JSON.stringify(firstModel.instances) === JSON.stringify(secondModel.instances) + ) + assert( + JSON.stringify(firstModel.services) === JSON.stringify(secondModel.services) + ) + + return true + } + + compareFormatted( + first: InstantiableCloudDevice<'response'>, + second: InstantiableCloudDevice<'response'> + ): boolean { + assert(DeviceOverviewRepositoryTestSuite.compareFormatted(first, second)) + assert(first.instantiateUrl === second.instantiateUrl) + assert(JSON.stringify(first.services) === JSON.stringify(second.services)) + + return true + } + + getFindOptionsWhere( + model?: InstantiableCloudDeviceModel + ): FindOptionsWhere { + return model + ? { + uuid: model?.uuid, + } + : { + uuid: '', + } + } +} + +export const instantiableCloudDeviceRepositoryTestSuite = + new InstantiableCloudDeviceRepositoryTestSuite() diff --git a/services/device/test/database/repositories/index.spec.ts b/services/device/test/database/repositories/index.spec.ts index 63e3239c..2f8a9855 100644 --- a/services/device/test/database/repositories/index.spec.ts +++ b/services/device/test/database/repositories/index.spec.ts @@ -10,7 +10,7 @@ import { } from '../../../src/database/model' import { deviceRepository } from '../../../src/database/repositories/device' import { peerconnectionRepository } from '../../../src/database/repositories/peerconnection' -import { deviceNames } from '../../data/device.spec' +import { deviceNames } from '../../data/devices/index.spec' import { prepareTestData, TestData } from '../../data/index.spec' import { peerconnectionNames } from '../../data/peerconnections/index.spec' import { deviceRepositoryTestSuite } from './device.spec' diff --git a/services/openapi/dist/openapi.json b/services/openapi/dist/openapi.json index 6910ac42..ebdfe201 100644 --- a/services/openapi/dist/openapi.json +++ b/services/openapi/dist/openapi.json @@ -306,6 +306,255 @@ "readOnly": true } }, + "required": [ + "url", + "type" + ], + "x-typeguard": true, + "x-service-name": "Device Service" + }, + "device_overview_init": { + "title": "Device Overview Init", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the device", + "writeOnly": true + }, + "description": { + "type": "string", + "description": "Extended description of the device, features, etc.", + "writeOnly": true + }, + "type": { + "type": "string", + "description": "Type of the device", + "enum": [ + "device", + "group", + "edge instantiable", + "cloud instantiable" + ], + "writeOnly": true + } + }, + "required": [ + "type" + ], + "x-service-name": "Device Service" + }, + "service_description": { + "title": "Service Description", + "type": "object", + "properties": { + "serviceType": { + "type": "string", + "format": "uri" + }, + "serviceId": { + "type": "string" + }, + "serviceDirection": { + "type": "string", + "enum": [ + "consumer", + "producer", + "prosumer" + ] + } + }, + "additionalProperties": true, + "x-service-name": "Device Service" + }, + "device_cloud_instantiable_init": { + "title": "Instantiable Cloud Device Init", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_init" + }, + { + "type": "object", + "properties": { + "type": { + "const": "cloud instantiable", + "writeOnly": true + }, + "instantiateUrl": { + "type": "string", + "format": "uri", + "writeOnly": true + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + }, + "writeOnly": true + } + }, + "required": [ + "type" + ] + } + ], + "x-service-name": "Device Service" + }, + "device_concrete_init": { + "title": "Concrete Device Init", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_init" + }, + { + "type": "object", + "properties": { + "type": { + "const": "device", + "writeOnly": true + }, + "experiment": { + "type": "string", + "format": "uri", + "writeOnly": true + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + }, + "writeOnly": true + } + }, + "required": [ + "type" + ] + } + ], + "x-service-name": "Device Service" + }, + "device_edge_instantiable_init": { + "title": "Instantiable Browser Device Init", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_init" + }, + { + "type": "object", + "properties": { + "type": { + "const": "edge instantiable", + "writeOnly": true + }, + "codeUrl": { + "type": "string", + "format": "uri", + "writeOnly": true + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + }, + "writeOnly": true + } + }, + "required": [ + "type" + ] + } + ], + "x-service-name": "Device Service" + }, + "device_reference": { + "title": "Device Reference", + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL of the device", + "format": "uri" + } + }, + "required": [ + "url" + ], + "x-service-name": "Device Service" + }, + "device_group_init": { + "title": "Device Group Init", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_init" + }, + { + "type": "object", + "properties": { + "type": { + "const": "group", + "writeOnly": true + }, + "devices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/device_reference" + }, + "writeOnly": true + } + }, + "required": [ + "type" + ] + } + ], + "x-service-name": "Device Service" + }, + "device_init": { + "title": "Device Init", + "oneOf": [ + { + "$ref": "#/components/schemas/device_cloud_instantiable_init" + }, + { + "$ref": "#/components/schemas/device_concrete_init" + }, + { + "$ref": "#/components/schemas/device_edge_instantiable_init" + }, + { + "$ref": "#/components/schemas/device_group_init" + } + ], + "x-service-name": "Device Service" + }, + "device_cloud_instantiable": { + "title": "Instantiable Cloud Device", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview" + }, + { + "type": "object", + "properties": { + "type": { + "const": "cloud instantiable" + }, + "instantiateUrl": { + "type": "string", + "format": "uri" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + } + } + }, + "required": [ + "type" + ] + } + ], "x-typeguard": true, "x-service-name": "Device Service" }, @@ -347,10 +596,12 @@ }, "connected": { "description": "If true, the device is connected to the service and can be used.\n", - "type": "boolean" + "type": "boolean", + "readOnly": true }, "announcedAvailability": { - "$ref": "#/components/schemas/availability" + "$ref": "#/components/schemas/availability", + "readOnly": true }, "experiment": { "type": "string", @@ -359,57 +610,47 @@ "services": { "type": "array", "items": { - "type": "object", - "additionalProperties": true + "$ref": "#/components/schemas/service_description" } } - } + }, + "required": [ + "type" + ] } ], "x-typeguard": true, "x-service-name": "Device Service" }, - "availability_rule": { - "title": "Availability Rule", - "type": "object", + "device_edge_instantiable": { + "title": "Instantiable Browser Device", "allOf": [ { - "$ref": "#/components/schemas/time_slot" + "$ref": "#/components/schemas/device_overview" }, { "type": "object", "properties": { - "available": { - "type": "boolean" + "type": { + "const": "edge instantiable" }, - "repeat": { - "description": "If specified the time slot is repeated in a fixed offset specified by the frequency", - "type": "object", - "properties": { - "frequency": { - "type": "string", - "enum": [ - "HOURLY", - "DAILY", - "WEEKLY", - "MONTHLY", - "YEARLY" - ] - }, - "until": { - "description": "Up to this date-time the time slot will be repeated.", - "type": "string", - "format": "date-time" - }, - "count": { - "description": "How often the time slot will be repeated", - "type": "integer" - } + "codeUrl": { + "type": "string", + "format": "uri" + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" } } - } + }, + "required": [ + "type" + ] } ], + "x-typeguard": true, "x-service-name": "Device Service" }, "device_group": { @@ -427,64 +668,211 @@ "devices": { "type": "array", "items": { - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "URL of the device", - "format": "uri" - } - } + "$ref": "#/components/schemas/device_reference" } } - } + }, + "required": [ + "type" + ] } ], "x-typeguard": true, "x-service-name": "Device Service" }, - "device_cloud_instantiable": { - "title": "Instantiable Cloud Device", + "device": { + "title": "Device", + "oneOf": [ + { + "$ref": "#/components/schemas/device_cloud_instantiable" + }, + { + "$ref": "#/components/schemas/device_concrete" + }, + { + "$ref": "#/components/schemas/device_edge_instantiable" + }, + { + "$ref": "#/components/schemas/device_group" + } + ], + "x-service-name": "Device Service" + }, + "device_overview_update": { + "title": "Device Overview Update", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the device", + "writeOnly": true + }, + "description": { + "type": "string", + "description": "Extended description of the device, features, etc.", + "writeOnly": true + } + }, + "x-service-name": "Device Service" + }, + "device_cloud_instantiable_update": { + "title": "Instantiable Cloud Device Update", "allOf": [ { - "$ref": "#/components/schemas/device_overview" + "$ref": "#/components/schemas/device_overview_update" }, { "type": "object", "properties": { - "type": { - "const": "cloud instantiable" - }, - "instantiate_url": { + "instantiateUrl": { "type": "string", - "format": "uri" + "format": "uri", + "writeOnly": true + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + }, + "writeOnly": true } } } ], - "x-typeguard": true, "x-service-name": "Device Service" }, - "device_edge_instantiable": { - "title": "Instantiable Browser Device", + "device_concrete_update": { + "title": "Concrete Device Update", "allOf": [ { - "$ref": "#/components/schemas/device_overview" + "$ref": "#/components/schemas/device_overview_update" }, { "type": "object", "properties": { - "type": { - "const": "edge instantiable" + "experiment": { + "type": "string", + "format": "uri", + "writeOnly": true }, - "code_url": { + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + }, + "writeOnly": true + } + } + } + ], + "x-service-name": "Device Service" + }, + "device_edge_instantiable_update": { + "title": "Instantiable Browser Device Update", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_update" + }, + { + "type": "object", + "properties": { + "codeUrl": { "type": "string", - "format": "uri" + "format": "uri", + "writeOnly": true + }, + "services": { + "type": "array", + "items": { + "$ref": "#/components/schemas/service_description" + }, + "writeOnly": true + } + } + } + ], + "x-service-name": "Device Service" + }, + "device_group_update": { + "title": "Device Group Update", + "allOf": [ + { + "$ref": "#/components/schemas/device_overview_update" + }, + { + "type": "object", + "properties": { + "devices": { + "type": "array", + "items": { + "$ref": "#/components/schemas/device_reference" + }, + "writeOnly": true + } + } + } + ], + "x-service-name": "Device Service" + }, + "device_update": { + "title": "Device Update", + "oneOf": [ + { + "$ref": "#/components/schemas/device_cloud_instantiable_update" + }, + { + "$ref": "#/components/schemas/device_concrete_update" + }, + { + "$ref": "#/components/schemas/device_edge_instantiable_update" + }, + { + "$ref": "#/components/schemas/device_group_update" + } + ], + "x-service-name": "Device Service" + }, + "availability_rule": { + "title": "Availability Rule", + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/time_slot" + }, + { + "type": "object", + "properties": { + "available": { + "type": "boolean" + }, + "repeat": { + "description": "If specified the time slot is repeated in a fixed offset specified by the frequency", + "type": "object", + "properties": { + "frequency": { + "type": "string", + "enum": [ + "HOURLY", + "DAILY", + "WEEKLY", + "MONTHLY", + "YEARLY" + ] + }, + "until": { + "description": "Up to this date-time the time slot will be repeated.", + "type": "string", + "format": "date-time" + }, + "count": { + "description": "How often the time slot will be repeated", + "type": "integer" + } + } } } } ], - "x-typeguard": true, "x-service-name": "Device Service" }, "message": { @@ -542,6 +930,11 @@ "type": "string" } }, + "required": [ + "serviceType", + "serviceId", + "remoteServiceId" + ], "additionalProperties": true, "x-service-name": "Device Service" }, @@ -561,7 +954,8 @@ "type": "string", "enum": [ "webrtc", - "websocket" + "websocket", + "local" ] }, "connectionUrl": { @@ -666,37 +1060,46 @@ "x-typeguard": true, "x-service-name": "Device Service" }, - "device_reference": { - "title": "Device Reference", + "peerconnection_common": { "type": "object", "properties": { "url": { "type": "string", - "description": "URL of the device", - "format": "uri" + "description": "URL of the peerconnection", + "format": "uri", + "readOnly": true + }, + "type": { + "type": "string", + "description": "Type of the peerconnection", + "enum": [ + "local", + "webrtc" + ] } }, "x-service-name": "Device Service" }, "peerconnection_overview": { "title": "Peerconnection Overview", - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "URL of the peerconnection", - "format": "uri", - "readOnly": true + "allOf": [ + { + "$ref": "#/components/schemas/peerconnection_common" }, - "devices": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": { - "$ref": "#/components/schemas/device_reference" + { + "type": "object", + "properties": { + "devices": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "$ref": "#/components/schemas/device_reference" + } + } } } - }, + ], "x-service-name": "Device Service" }, "configured_device_reference": { @@ -720,13 +1123,16 @@ } } }, + "required": [ + "url" + ], "x-service-name": "Device Service" }, "peerconnection": { "title": "Peerconnection", "allOf": [ { - "$ref": "#/components/schemas/peerconnection_overview" + "$ref": "#/components/schemas/peerconnection_common" }, { "type": "object", @@ -742,6 +1148,7 @@ "status": { "type": "string", "description": "The status of the peerconnection.", + "readOnly": true, "enum": [ "waiting-for-devices", "connected", @@ -779,7 +1186,7 @@ }, "x-service-name": "Experiment Service" }, - "device": { + "schemas-device": { "title": "Device", "type": "object", "properties": { @@ -878,7 +1285,7 @@ "type": "array", "description": "Devices associated with the experiment", "items": { - "$ref": "#/components/schemas/device" + "$ref": "#/components/schemas/schemas-device" } }, "roles": { @@ -2926,36 +3333,7 @@ "content": { "application/json": { "schema": { - "title": "Device Init", - "anyOf": [ - { - "allOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "type": "object", - "properties": { - "announcedAvailability": { - "type": "array", - "items": { - "$ref": "#/components/schemas/availability_rule" - } - } - } - } - ] - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device_init" }, "examples": { "microcontroller": { @@ -3069,20 +3447,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device" }, "examples": { "microcontroller": { @@ -3305,20 +3670,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device" }, "examples": { "microcontroller": { @@ -3471,36 +3823,7 @@ "content": { "application/json": { "schema": { - "title": "Device Init", - "anyOf": [ - { - "allOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "type": "object", - "properties": { - "announcedAvailability": { - "type": "array", - "items": { - "$ref": "#/components/schemas/availability_rule" - } - } - } - } - ] - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device_update" }, "examples": { "microcontroller": { @@ -3614,20 +3937,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/device_concrete" - }, - { - "$ref": "#/components/schemas/device_group" - }, - { - "$ref": "#/components/schemas/device_cloud_instantiable" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable" - } - ] + "$ref": "#/components/schemas/device" }, "examples": { "microcontroller": { From 120e2a41fb0dd34fcee03e1de33243ec0ea09b55 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Thu, 23 Mar 2023 10:41:17 +0100 Subject: [PATCH 10/33] WIP: Update API - add new route to update connection state of devices - make url, type and name required on a device - add new init and update types for devices - update connection state definition - add connection-state-changed message - apply changes and implement new route (WIP) --- services/device/api/openapi.yml | 4 + services/device/api/parameters/device_url.yml | 8 + .../peerconnection_device_status.yml | 39 ++++ .../devices/device_cloud_instantiable.yml | 2 - .../api/schemas/devices/device_concrete.yml | 2 - .../devices/device_edge_instantiable.yml | 2 - .../api/schemas/devices/device_group.yml | 2 - .../api/schemas/devices/device_overview.yml | 1 + .../devices/init/device_overview_init.yml | 3 +- .../connection_state_changed_message.yml | 17 ++ .../peerconnections/peerconnection.yml | 11 +- .../peerconnections/peerconnection_common.yml | 7 +- .../peerconnection_overview.yml | 4 +- .../peerconnections/peerconnection_status.yml | 11 ++ services/device/dist/openapi.json | 171 ++++++++++++++---- services/device/package.json | 2 +- services/device/src/database/model.ts | 38 ++-- .../src/database/repositories/device.ts | 15 ++ .../repositories/device/concreteDevice.ts | 18 +- .../repositories/device/deviceGroup.ts | 1 - .../device/instantiableBrowserDevice.ts | 1 - .../device/instantiableCloudDevice.ts | 1 - .../database/repositories/peerconnection.ts | 6 +- services/device/src/methods/availability.ts | 15 +- services/device/src/methods/callbacks.ts | 26 ++- services/device/src/methods/signaling.ts | 49 +++-- .../callbacks/event/deviceChanged.ts | 51 +++--- .../src/operations/callbacks/event/index.ts | 10 +- .../device/src/operations/callbacks/index.ts | 6 +- .../devices/device/availability/post.ts | 25 ++- .../src/operations/devices/device/delete.ts | 11 +- .../src/operations/devices/device/get.ts | 6 +- .../src/operations/devices/device/patch.ts | 30 +-- .../src/operations/devices/device/post.ts | 57 ++---- .../devices/device/signaling/post.ts | 22 +-- .../devices/device/websocket/post.ts | 36 ++-- services/device/src/operations/devices/get.ts | 7 +- .../device/src/operations/devices/post.ts | 14 +- .../src/operations/devices/websocket/index.ts | 158 +++++++++------- .../devices/websocket/messageHandling.ts | 73 ++++---- .../src/operations/peerconnections/get.ts | 5 +- .../peerconnections/peerconnection/delete.ts | 46 +++-- .../peerconnection/device_status/index.ts | 1 + .../peerconnection/device_status/patch.ts | 77 ++++++++ .../peerconnections/peerconnection/get.ts | 4 +- .../peerconnections/peerconnection/index.ts | 1 + .../src/operations/peerconnections/post.ts | 63 +++---- services/device/tsconfig.build.json | 9 + 48 files changed, 704 insertions(+), 464 deletions(-) create mode 100644 services/device/api/parameters/device_url.yml create mode 100644 services/device/api/resources/peerconnection_device_status.yml create mode 100644 services/device/api/schemas/messages/connection_state_changed_message.yml create mode 100644 services/device/api/schemas/peerconnections/peerconnection_status.yml create mode 100644 services/device/src/operations/peerconnections/peerconnection/device_status/index.ts create mode 100644 services/device/src/operations/peerconnections/peerconnection/device_status/patch.ts create mode 100644 services/device/tsconfig.build.json diff --git a/services/device/api/openapi.yml b/services/device/api/openapi.yml index df919b38..1adc2994 100644 --- a/services/device/api/openapi.yml +++ b/services/device/api/openapi.yml @@ -20,6 +20,8 @@ components: schemas: authentication_message: $ref: "./schemas/messages/authentication_message.yml" + connection_state_changed_message: + $ref: "./schemas/messages/connection_state_changed_message.yml" tags: - name: device description: |- @@ -42,3 +44,5 @@ paths: $ref: "./resources/peerconnections.yml" /peerconnections/{peerconnection_id}: $ref: "./resources/peerconnection.yml" + /peerconnections/{peerconnection_id}/device_status: + $ref: "./resources/peerconnection_device_status.yml" diff --git a/services/device/api/parameters/device_url.yml b/services/device/api/parameters/device_url.yml new file mode 100644 index 00000000..99073713 --- /dev/null +++ b/services/device/api/parameters/device_url.yml @@ -0,0 +1,8 @@ +# yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-parameter.json +in: query +name: device_url +description: URL of the device +required: true +schema: + type: string + format: uri diff --git a/services/device/api/resources/peerconnection_device_status.yml b/services/device/api/resources/peerconnection_device_status.yml new file mode 100644 index 00000000..d913dd97 --- /dev/null +++ b/services/device/api/resources/peerconnection_device_status.yml @@ -0,0 +1,39 @@ +# yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-resource.json +patch: + operationId: patch_peerconnection_device_status + summary: Sets the peerconnection status of a single device. + tags: + - peerconnection + security: + # TODO + - JWT: + - peerconnection + - peerconnection:list + requestBody: + required: true + description: The JSON Representation of the device peer connection. + content: + application/json: + schema: + type: object + properties: + status: + $ref: ../schemas/peerconnections/peerconnection_status.yml + required: + - status + responses: + 201: + description: OK. + 400: + description: Bad Request. + 401: + description: Unauthorized. + 403: + description: Forbidden. + 404: + description: Resource not found. + 500: + description: Server Error. + parameters: + - $ref: '../parameters/peerconnection_id.yml' + - $ref: '../parameters/device_url.yml' diff --git a/services/device/api/schemas/devices/device_cloud_instantiable.yml b/services/device/api/schemas/devices/device_cloud_instantiable.yml index 93bec0f3..06467303 100644 --- a/services/device/api/schemas/devices/device_cloud_instantiable.yml +++ b/services/device/api/schemas/devices/device_cloud_instantiable.yml @@ -13,6 +13,4 @@ allOf: type: array items: $ref: ./services/service_description.yml - required: - - type x-typeguard: true diff --git a/services/device/api/schemas/devices/device_concrete.yml b/services/device/api/schemas/devices/device_concrete.yml index 372a8584..49cd6f03 100644 --- a/services/device/api/schemas/devices/device_concrete.yml +++ b/services/device/api/schemas/devices/device_concrete.yml @@ -21,6 +21,4 @@ allOf: type: array items: $ref: ./services/service_description.yml - required: - - type x-typeguard: true diff --git a/services/device/api/schemas/devices/device_edge_instantiable.yml b/services/device/api/schemas/devices/device_edge_instantiable.yml index ce800e6e..8e3ff43f 100644 --- a/services/device/api/schemas/devices/device_edge_instantiable.yml +++ b/services/device/api/schemas/devices/device_edge_instantiable.yml @@ -13,6 +13,4 @@ allOf: type: array items: $ref: ./services/service_description.yml - required: - - type x-typeguard: true diff --git a/services/device/api/schemas/devices/device_group.yml b/services/device/api/schemas/devices/device_group.yml index 46b99f57..de61e320 100644 --- a/services/device/api/schemas/devices/device_group.yml +++ b/services/device/api/schemas/devices/device_group.yml @@ -10,6 +10,4 @@ allOf: type: array items: $ref: ./device_reference.yml - required: - - type x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/devices/device_overview.yml b/services/device/api/schemas/devices/device_overview.yml index fbdb477e..2f09ca06 100644 --- a/services/device/api/schemas/devices/device_overview.yml +++ b/services/device/api/schemas/devices/device_overview.yml @@ -28,4 +28,5 @@ properties: required: - url - type + - name x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/devices/init/device_overview_init.yml b/services/device/api/schemas/devices/init/device_overview_init.yml index 734acbc4..fc40260f 100644 --- a/services/device/api/schemas/devices/init/device_overview_init.yml +++ b/services/device/api/schemas/devices/init/device_overview_init.yml @@ -20,4 +20,5 @@ properties: - cloud instantiable writeOnly: true required: - - type \ No newline at end of file + - type + - name \ No newline at end of file diff --git a/services/device/api/schemas/messages/connection_state_changed_message.yml b/services/device/api/schemas/messages/connection_state_changed_message.yml new file mode 100644 index 00000000..dbdbd269 --- /dev/null +++ b/services/device/api/schemas/messages/connection_state_changed_message.yml @@ -0,0 +1,17 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Connection State Changed Message +allOf: + - $ref: "./message.yml" + - type: object + properties: + messageType: + const: connection-state-changed + connectionUrl: + type: string + format: uri + status: + $ref: ../peerconnections/peerconnection_status.yml + required: + - connectionUrl + - status +x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/peerconnections/peerconnection.yml b/services/device/api/schemas/peerconnections/peerconnection.yml index 380e5dcc..dc95cda4 100644 --- a/services/device/api/schemas/peerconnections/peerconnection.yml +++ b/services/device/api/schemas/peerconnections/peerconnection.yml @@ -10,13 +10,6 @@ allOf: maxItems: 2 items: $ref: "../devices/configured_device_reference.yml" - status: - type: string - description: The status of the peerconnection. - readOnly: true - enum: - - waiting-for-devices - - connected - - failed - - closed + required: + - devices x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/peerconnections/peerconnection_common.yml b/services/device/api/schemas/peerconnections/peerconnection_common.yml index 5295f831..7a0ae394 100644 --- a/services/device/api/schemas/peerconnections/peerconnection_common.yml +++ b/services/device/api/schemas/peerconnections/peerconnection_common.yml @@ -11,4 +11,9 @@ properties: description: Type of the peerconnection enum: - local - - webrtc \ No newline at end of file + - webrtc + status: + $ref: ./peerconnection_status.yml +required: + - url + - type \ No newline at end of file diff --git a/services/device/api/schemas/peerconnections/peerconnection_overview.yml b/services/device/api/schemas/peerconnections/peerconnection_overview.yml index e5eeb93d..f38d1400 100644 --- a/services/device/api/schemas/peerconnections/peerconnection_overview.yml +++ b/services/device/api/schemas/peerconnections/peerconnection_overview.yml @@ -9,4 +9,6 @@ allOf: minItems: 2 maxItems: 2 items: - $ref: "../devices/device_reference.yml" \ No newline at end of file + $ref: "../devices/device_reference.yml" + required: + - devices \ No newline at end of file diff --git a/services/device/api/schemas/peerconnections/peerconnection_status.yml b/services/device/api/schemas/peerconnections/peerconnection_status.yml new file mode 100644 index 00000000..84b63375 --- /dev/null +++ b/services/device/api/schemas/peerconnections/peerconnection_status.yml @@ -0,0 +1,11 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Connection Status +type: string +description: The status of the peerconnection. +enum: + - new + - connecting + - connected + - disconnected + - failed + - closed \ No newline at end of file diff --git a/services/device/dist/openapi.json b/services/device/dist/openapi.json index 8e97f47e..d8f34d39 100644 --- a/services/device/dist/openapi.json +++ b/services/device/dist/openapi.json @@ -42,6 +42,34 @@ ], "x-typeguard": true }, + "connection_state_changed_message": { + "title": "Connection State Changed Message", + "allOf": [ + { + "$ref": "#/components/schemas/message" + }, + { + "type": "object", + "properties": { + "messageType": { + "const": "connection-state-changed" + }, + "connectionUrl": { + "type": "string", + "format": "uri" + }, + "status": { + "$ref": "#/components/schemas/peerconnection_status" + } + }, + "required": [ + "connectionUrl", + "status" + ] + } + ], + "x-typeguard": true + }, "device_overview": { "title": "Device Overview", "type": "object", @@ -78,7 +106,8 @@ }, "required": [ "url", - "type" + "type", + "name" ], "x-typeguard": true }, @@ -109,7 +138,8 @@ } }, "required": [ - "type" + "type", + "name" ] }, "service_description": { @@ -310,10 +340,7 @@ "$ref": "#/components/schemas/service_description" } } - }, - "required": [ - "type" - ] + } } ], "x-typeguard": true @@ -371,10 +398,7 @@ "$ref": "#/components/schemas/service_description" } } - }, - "required": [ - "type" - ] + } } ], "x-typeguard": true @@ -401,10 +425,7 @@ "$ref": "#/components/schemas/service_description" } } - }, - "required": [ - "type" - ] + } } ], "x-typeguard": true @@ -427,10 +448,7 @@ "$ref": "#/components/schemas/device_reference" } } - }, - "required": [ - "type" - ] + } } ], "x-typeguard": true @@ -801,6 +819,19 @@ ], "x-typeguard": true }, + "peerconnection_status": { + "title": "Connection Status", + "type": "string", + "description": "The status of the peerconnection.", + "enum": [ + "new", + "connecting", + "connected", + "disconnected", + "failed", + "closed" + ] + }, "peerconnection_common": { "type": "object", "properties": { @@ -817,8 +848,15 @@ "local", "webrtc" ] + }, + "status": { + "$ref": "#/components/schemas/peerconnection_status" } - } + }, + "required": [ + "url", + "type" + ] }, "peerconnection_overview": { "title": "Peerconnection Overview", @@ -837,7 +875,10 @@ "$ref": "#/components/schemas/device_reference" } } - } + }, + "required": [ + "devices" + ] } ] }, @@ -882,19 +923,11 @@ "items": { "$ref": "#/components/schemas/configured_device_reference" } - }, - "status": { - "type": "string", - "description": "The status of the peerconnection.", - "readOnly": true, - "enum": [ - "waiting-for-devices", - "connected", - "failed", - "closed" - ] } - } + }, + "required": [ + "devices" + ] } ], "x-typeguard": true @@ -979,6 +1012,16 @@ "example": [ "f4c69c42-6e1c-44c3-8e44-f74bd22c3713" ] + }, + "device_url": { + "in": "query", + "name": "device_url", + "description": "URL of the device", + "required": true, + "schema": { + "type": "string", + "format": "uri" + } } } }, @@ -2537,6 +2580,70 @@ } ] } + }, + "/peerconnections/{peerconnection_id}/device_status": { + "patch": { + "operationId": "patch_peerconnection_device_status", + "summary": "Sets the peerconnection status of a single device.", + "tags": [ + "peerconnection" + ], + "security": [ + { + "JWT": [ + "peerconnection", + "peerconnection:list" + ] + } + ], + "requestBody": { + "required": true, + "description": "The JSON Representation of the device peer connection.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "$ref": "#/components/schemas/peerconnection_status" + } + }, + "required": [ + "status" + ] + } + } + } + }, + "responses": { + "201": { + "description": "OK." + }, + "400": { + "description": "Bad Request." + }, + "401": { + "description": "Unauthorized." + }, + "403": { + "description": "Forbidden." + }, + "404": { + "description": "Resource not found." + }, + "500": { + "description": "Server Error." + } + }, + "parameters": [ + { + "$ref": "#/components/parameters/peerconnection_id" + }, + { + "$ref": "#/components/parameters/device_url" + } + ] + } } } } \ No newline at end of file diff --git a/services/device/package.json b/services/device/package.json index fb2babc0..ba98ad82 100644 --- a/services/device/package.json +++ b/services/device/package.json @@ -14,7 +14,7 @@ "watch-openapi": "npx --yes chokidar-cli 'api/**/*.yml' -c 'npm run openapi-bundle'", "watch-rapidoc": "npx --yes browser-sync start --server --startPath 'api/rapidoc.html' --files 'dist/openapi.json'", "build-generate-code": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service -o src/generated", - "build-compile": "tsc", + "build-compile": "tsc --project tsconfig.build.json", "build": "npm run build-generate-code && npm run build-compile", "start": "node app/index.js", "dev": "env-cmd -e development npx nodemon src/index.ts", diff --git a/services/device/src/database/model.ts b/services/device/src/database/model.ts index e69f7efb..24627142 100644 --- a/services/device/src/database/model.ts +++ b/services/device/src/database/model.ts @@ -1,7 +1,9 @@ import { AvailabilityRule, + ConfiguredDeviceReference, + ConnectionStatus, DeviceReference, - Peerconnection, + ServiceDescription, TimeSlot, } from '../generated/types' import { @@ -33,7 +35,7 @@ export abstract class DeviceOverviewModel { @PrimaryGeneratedColumn('uuid') uuid!: string @Column() - name?: string + name!: string @Column({ nullable: true }) description?: string @Column() @@ -68,7 +70,7 @@ export class ConcreteDeviceModel extends DeviceOverviewModel { @Column() token?: string @Column('simple-json') - services?: { [k: string]: any }[] + services?: ServiceDescription[] @ManyToOne( () => InstantiableDeviceOverviewModel, (instantiableDevice) => instantiableDevice.instances @@ -91,7 +93,7 @@ export class InstantiableCloudDeviceModel extends InstantiableDeviceOverviewMode @Column() instantiateUrl?: string @Column('simple-json') - services?: { [k: string]: any }[] + services?: ServiceDescription[] } @ChildEntity('edge instantiable') @@ -101,7 +103,7 @@ export class InstantiableBrowserDeviceModel extends InstantiableDeviceOverviewMo @Column() codeUrl?: string @Column('simple-json') - services?: { [k: string]: any }[] + services?: ServiceDescription[] } @Entity({ name: 'Peerconnection' }) @@ -109,31 +111,13 @@ export abstract class PeerconnectionModel { @PrimaryGeneratedColumn('uuid') uuid!: string @Column() - type?: 'local' | 'webrtc' + type!: 'local' | 'webrtc' @Column() - status!: 'waiting-for-devices' | 'connected' | 'failed' | 'closed' + status!: ConnectionStatus @Column('simple-json') - deviceA!: NonNullable[number] & { - url: string - config?: { - services?: { - serviceType: string - serviceId: string - remoteServiceId: string - }[] - } - } + deviceA!: ConfiguredDeviceReference & { status: ConnectionStatus } @Column('simple-json') - deviceB!: NonNullable[number] & { - url: string - config?: { - services?: { - serviceType: string - serviceId: string - remoteServiceId: string - }[] - } - } + deviceB!: ConfiguredDeviceReference & { status: ConnectionStatus } @DeleteDateColumn() deletedAt?: Date } diff --git a/services/device/src/database/repositories/device.ts b/services/device/src/database/repositories/device.ts index d4c4d121..956c9ee9 100644 --- a/services/device/src/database/repositories/device.ts +++ b/services/device/src/database/repositories/device.ts @@ -69,6 +69,21 @@ export class DeviceRepository extends AbstractRepository< return await deviceGroupRepository.format(model, options?.flatGroup) } } + + async save(model: DeviceModel): Promise { + if (!this.repository) this.throwUninitializedRepositoryError() + + switch (model.type) { + case 'cloud instantiable': + return await instantiableCloudDeviceRepository.save(model) + case 'device': + return await concreteDeviceRepository.save(model) + case 'edge instantiable': + return await instantiableBrowserDeviceRepository.save(model) + case 'group': + return await deviceGroupRepository.save(model) + } + } } export const deviceRepository = new DeviceRepository() diff --git a/services/device/src/database/repositories/device/concreteDevice.ts b/services/device/src/database/repositories/device/concreteDevice.ts index 1f82397b..24d0a1bd 100644 --- a/services/device/src/database/repositories/device/concreteDevice.ts +++ b/services/device/src/database/repositories/device/concreteDevice.ts @@ -25,7 +25,6 @@ export class ConcreteDeviceRepository extends AbstractRepository< async create(data?: ConcreteDeviceInit<'request'>): Promise { const model = await super.create(data) - model.type = 'device' return model } @@ -43,19 +42,10 @@ export class ConcreteDeviceRepository extends AbstractRepository< return { ...(await DeviceOverviewRepository.format(model)), type: 'device', - announcedAvailability: model.announcedAvailability - ? model.announcedAvailability.map((timeSlot) => { - return { - start: new Date(timeSlot.start).toISOString(), - end: new Date(timeSlot.end).toISOString(), - } - }) - : undefined, - connected: model.connected !== undefined ? model.connected : undefined, - experiment: model.experiment ? model.experiment : undefined, - services: model.services - ? model.services.map((service) => JSON.parse(service.description)) - : undefined, + announcedAvailability: model.announcedAvailability, + connected: model.connected, + experiment: model.experiment, + services: model.services, } } } diff --git a/services/device/src/database/repositories/device/deviceGroup.ts b/services/device/src/database/repositories/device/deviceGroup.ts index 7ccaae2c..4be7b99b 100644 --- a/services/device/src/database/repositories/device/deviceGroup.ts +++ b/services/device/src/database/repositories/device/deviceGroup.ts @@ -28,7 +28,6 @@ export class DeviceGroupRepository extends AbstractRepository< async create(data?: DeviceGroupInit<'request'>): Promise { const model = await super.create(data) - model.type = 'group' return model } diff --git a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts index 00a1ef35..93865a1b 100644 --- a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts +++ b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts @@ -27,7 +27,6 @@ export class InstantiableBrowserDeviceRepository extends AbstractRepository< data?: InstantiableBrowserDeviceInit<'request'> ): Promise { const model = await super.create(data) - model.type = 'edge instantiable' return model } diff --git a/services/device/src/database/repositories/device/instantiableCloudDevice.ts b/services/device/src/database/repositories/device/instantiableCloudDevice.ts index a5282af9..140fbe45 100644 --- a/services/device/src/database/repositories/device/instantiableCloudDevice.ts +++ b/services/device/src/database/repositories/device/instantiableCloudDevice.ts @@ -27,7 +27,6 @@ export class InstantiableCloudDeviceRepository extends AbstractRepository< data?: InstantiableCloudDeviceInit<'request'> ): Promise { const model = await super.create(data) - model.type = 'cloud instantiable' return model } diff --git a/services/device/src/database/repositories/peerconnection.ts b/services/device/src/database/repositories/peerconnection.ts index e1601569..3f8d0ca8 100644 --- a/services/device/src/database/repositories/peerconnection.ts +++ b/services/device/src/database/repositories/peerconnection.ts @@ -22,7 +22,7 @@ export class PeerconnectionRepository extends AbstractRepository< async create(data?: Peerconnection<'request'>): Promise { const model = await super.create(data) - model.status = 'waiting-for-devices' + model.status = 'new' return model } @@ -49,8 +49,8 @@ export class PeerconnectionRepository extends AbstractRepository< ) } - model.deviceA = deviceA - model.deviceB = deviceB + model.deviceA = { ...deviceA, status: 'new' } + model.deviceB = { ...deviceB, status: 'new' } } } diff --git a/services/device/src/methods/availability.ts b/services/device/src/methods/availability.ts index 5c668bb6..0e59ae71 100644 --- a/services/device/src/methods/availability.ts +++ b/services/device/src/methods/availability.ts @@ -12,25 +12,18 @@ type AvailabilityRuleModel = Omit, 'start' | 'end' } /** - * This function applies a list of availability rules to a list of timeslots. - * @param availability The list of timeslots to which to apply the availability rule. + * This function calculates a list of timeslots from a list of availability rules. * @param availabilityRules The list of availability rules to be applied. * @param start The start time for the availability rules. * @param end The end time for the availability rules. - * @returns The list of timeslots containing the changes of the applied availability rules. + * @returns The list of available timeslots. */ -export function applyAvailabilityRules( - availability: Required[], +export function calculateAvailability( availabilityRules: AvailabilityRule[], start: number, end: number ): Required[] { - let newAvailability = availability.map((timeSlot) => { - return { - start: Date.parse(timeSlot.start), - end: Date.parse(timeSlot.end), - } - }) + let newAvailability: TimeSlotModel[] = [] for (const availabilityRule of availabilityRules) { newAvailability = applyAvailabilityRule( newAvailability, diff --git a/services/device/src/methods/callbacks.ts b/services/device/src/methods/callbacks.ts index d2493160..53eb1540 100644 --- a/services/device/src/methods/callbacks.ts +++ b/services/device/src/methods/callbacks.ts @@ -2,6 +2,7 @@ import { config } from '../config' import { DeviceModel, PeerconnectionModel } from '../database/model' import { deviceRepository } from '../database/repositories/device' import { peerconnectionRepository } from '../database/repositories/peerconnection' +import { deviceUrlFromId, peerconnectionUrlFromId } from './urlFromId' import fetch from 'node-fetch' export const callbackUrl: string = @@ -11,14 +12,18 @@ export const closedCallbacks = new Map>() export const statusChangedCallbacks = new Map>() /** - * This function sends a "device-changed" callback. + * This function sends a 'device-changed' callback. * @param device The device for which to send the callback. */ export async function sendChangedCallback(device: DeviceModel) { - console.log(`Sending changedCallback for device ${device.uuid}`) const urls = changedCallbacks.get(device.uuid) ?? [] for (const url of urls) { - console.log(`Sending changedCallback for device ${device.uuid} to url ${url}`) + console.log( + `Sending changed-callback for device '${deviceUrlFromId( + device.uuid + )}' to '${url}'` + ) + const res = await fetch(url, { method: 'POST', body: JSON.stringify({ @@ -40,12 +45,18 @@ export async function sendChangedCallback(device: DeviceModel) { } /** - * This function sends a "peerconnection-closed" callback. + * This function sends a 'peerconnection-closed' callback. * @param peerconnection The peerconnection for which to send the callback. */ export async function sendClosedCallback(peerconnection: PeerconnectionModel) { const urls = closedCallbacks.get(peerconnection.uuid) ?? [] for (const url of urls) { + console.log( + `Sending closed-callback for peerconnection '${peerconnectionUrlFromId( + peerconnection.uuid + )}' to '${url}'` + ) + const res = await fetch(url, { method: 'post', body: JSON.stringify({ @@ -67,15 +78,16 @@ export async function sendClosedCallback(peerconnection: PeerconnectionModel) { } /** - * This function sends a "peerconnection-status-changed" callback. + * This function sends a 'peerconnection-status-changed' callback. * @param peerconnection The peerconnection for which to send the callback. */ export async function sendStatusChangedCallback(peerconnection: PeerconnectionModel) { - console.log(`Sending statusChangedCallback for peerconnection ${peerconnection.uuid}`) const urls = statusChangedCallbacks.get(peerconnection.uuid) ?? [] for (const url of urls) { console.log( - `Sending statusChangedCallback for peerconnection ${peerconnection.uuid} to url ${url}` + `Sending status-changed-callback for peerconnection '${peerconnectionUrlFromId( + peerconnection.uuid + )}' to '${url}'` ) const res = await fetch(url, { method: 'post', diff --git a/services/device/src/methods/signaling.ts b/services/device/src/methods/signaling.ts index c8ead030..57c64744 100644 --- a/services/device/src/methods/signaling.ts +++ b/services/device/src/methods/signaling.ts @@ -2,7 +2,6 @@ import { AppDataSource } from '../database/dataSource' import { PeerconnectionModel } from '../database/model' import { CreatePeerconnectionMessage } from '../generated/types' import { apiClient } from '../globals' -import { sendStatusChangedCallback } from './callbacks' import { peerconnectionUrlFromId } from './urlFromId' import Queue from 'queue' @@ -21,8 +20,7 @@ class SignalingQueue { try { await startSignaling(peerconnection.uuid) } catch (error) { - if (error instanceof Error) console.log(error.message) - else console.log(error) + console.error(error) } }) } @@ -37,9 +35,9 @@ export const signalingQueue = new SignalingQueue() */ async function startSignaling(peerconnectionId: string) { console.log(`Starting signaling for ${peerconnectionId}`) - const peerconnectionRepository = AppDataSource.getRepository(PeerconnectionModel) - const peerconnection = await peerconnectionRepository.findOneOrFail({ + const peerconnectionRepository = AppDataSource.getRepository(PeerconnectionModel) + const peerconnectionModel = await peerconnectionRepository.findOneOrFail({ where: { uuid: peerconnectionId, }, @@ -53,9 +51,11 @@ async function startSignaling(peerconnectionId: string) { }, }) - if (peerconnection.status !== 'waiting-for-devices') { + if (peerconnectionModel.status !== 'new') { console.log( - `status of peerconnection '${peerconnection.uuid}' is not 'waiting-for-devices', '${peerconnection.status}'` + `status of peerconnection '${peerconnectionUrlFromId( + peerconnectionModel.uuid + )}' is not 'new', '${peerconnectionModel.status}'` ) return } @@ -64,43 +64,38 @@ async function startSignaling(peerconnectionId: string) { messageType: 'command', command: 'createPeerconnection', connectionType: 'webrtc', - connectionUrl: peerconnectionUrlFromId(peerconnection.uuid), + connectionUrl: peerconnectionUrlFromId(peerconnectionModel.uuid), } const createPeerConnectionMessageA: CreatePeerconnectionMessage = { ...common, - services: peerconnection.deviceA.config?.services - ? peerconnection.deviceA.config.services + services: peerconnectionModel.deviceA.config?.services + ? peerconnectionModel.deviceA.config.services : [], tiebreaker: false, } const createPeerConnectionMessageB: CreatePeerconnectionMessage = { ...common, - services: peerconnection.deviceB.config?.services - ? peerconnection.deviceB.config.services + services: peerconnectionModel.deviceB.config?.services + ? peerconnectionModel.deviceB.config.services : [], tiebreaker: true, } - // TODO: check what problems may occur here and address them accordingly - const response1 = apiClient.sendSignalingMessage( - peerconnection.deviceA.url, + // TODO: find out how to handle the different possible errors + peerconnectionModel.status = 'connecting' + await peerconnectionRepository.save(peerconnectionModel) + + await apiClient.sendSignalingMessage( + peerconnectionModel.deviceA.url, createPeerConnectionMessageA, - peerconnectionUrlFromId(peerconnection.uuid) + peerconnectionUrlFromId(peerconnectionModel.uuid) ) - const response2 = apiClient.sendSignalingMessage( - peerconnection.deviceB.url, + await apiClient.sendSignalingMessage( + peerconnectionModel.deviceB.url, createPeerConnectionMessageB, - peerconnectionUrlFromId(peerconnection.uuid) + peerconnectionUrlFromId(peerconnectionModel.uuid) ) - - await Promise.all([response1, response2]) - - // NOTE: this behaviour should maybe be changed later on - peerconnection.status = 'connected' - await AppDataSource.getRepository(PeerconnectionModel).save(peerconnection) - - await sendStatusChangedCallback(peerconnection) } diff --git a/services/device/src/operations/callbacks/event/deviceChanged.ts b/services/device/src/operations/callbacks/event/deviceChanged.ts index b41ca993..fd85adda 100644 --- a/services/device/src/operations/callbacks/event/deviceChanged.ts +++ b/services/device/src/operations/callbacks/event/deviceChanged.ts @@ -1,5 +1,6 @@ import { peerconnectionRepository } from '../../../database/repositories/peerconnection' import { + ConcreteDevice, isConcreteDevice, isDeviceGroup, isInstantiableBrowserDevice, @@ -7,25 +8,26 @@ import { } from '../../../generated/types' import { apiClient, timeoutMap } from '../../../globals' import { signalingQueue } from '../../../methods/signaling' -import { MalformedBodyError, InvalidValueError } from '@crosslab/service-common' +import { MalformedBodyError } from '@crosslab/service-common' /** * This function handles an incoming "device-changed" event callback. * @param callback The incoming "device-changed" callback to be handled. * @throws {MalformedBodyError} Thrown if the callback is malformed. - * @throws {InvalidValueError} Thrown if the device is not of type "device". * @returns The status code for the response to the incoming callback. */ -export async function handleDeviceChangedEventCallback( - callback: any -): Promise<200 | 410> { +export async function handleDeviceChangedEventCallback(callback: { + [k: string]: unknown +}): Promise<200 | 410> { if (!callback.device) { throw new MalformedBodyError( - 'Event-callbacks of type "device-changed" require property "device"', + "Event-callbacks of type 'device-changed' require property 'device'", 400 ) } + const device = callback.device + if ( !isConcreteDevice(device) && !isDeviceGroup(device) && @@ -34,43 +36,39 @@ export async function handleDeviceChangedEventCallback( ) { throw new MalformedBodyError('Property "device" is not a valid device', 400) } + if (!device.url) { throw new MalformedBodyError('Property "device" is missing url', 400) } - if (!isConcreteDevice(device)) { - throw new InvalidValueError( - `Device needs to be of type "device" but is of type "${device.type}"`, - 400 // NOTE: error code - ) + + if (isConcreteDevice(device)) { + return await handleConcreteDevice(device) + } else { + return 410 } +} + +async function handleConcreteDevice(concreteDevice: ConcreteDevice) { const pendingConnectionsA = await peerconnectionRepository.find({ where: { - status: 'waiting-for-devices', + status: 'connecting', deviceA: { - url: device.url, + url: concreteDevice.url, }, }, - relations: { - deviceA: true, - deviceB: true, - }, }) + const pendingConnectionsB = await peerconnectionRepository.find({ where: { - status: 'waiting-for-devices', + status: 'connecting', deviceB: { - url: device.url, + url: concreteDevice.url, }, }, - relations: { - deviceA: true, - deviceB: true, - }, }) + const pendingConnections = [...pendingConnectionsA, ...pendingConnectionsB] - if (pendingConnections.length === 0) { - return 410 // TODO: check if 410 is the right choice here - } + for (const pendingConnection of pendingConnections) { const deviceA = await apiClient.getDevice(pendingConnection.deviceA.url) const deviceB = await apiClient.getDevice(pendingConnection.deviceB.url) @@ -81,5 +79,6 @@ export async function handleDeviceChangedEventCallback( timeoutMap.delete(pendingConnection.uuid) } } + return pendingConnections.length === 0 ? 410 : 200 } diff --git a/services/device/src/operations/callbacks/event/index.ts b/services/device/src/operations/callbacks/event/index.ts index 9368aecd..f45f5843 100644 --- a/services/device/src/operations/callbacks/event/index.ts +++ b/services/device/src/operations/callbacks/event/index.ts @@ -8,16 +8,18 @@ import { MalformedBodyError, InvalidValueError } from '@crosslab/service-common' * @throws {InvalidValueError} Thrown if the type of the event callback is unknown. * @returns The status code of the callback response. */ -export async function handleEventCallback(callback: any): Promise<200 | 410> { +export async function handleEventCallback(callback: { + [k: string]: unknown +}): Promise<200 | 410> { if (!callback.eventType) { throw new MalformedBodyError( - 'Callbacks of type "event" require property "eventType"', + "Callbacks of type 'event' require property 'eventType'", 400 ) } if (typeof callback.eventType !== 'string') { throw new MalformedBodyError( - 'Property "callbackType" needs to be of type "string"', + "Property 'callbackType' needs to be of type 'string'", 400 ) } @@ -26,7 +28,7 @@ export async function handleEventCallback(callback: any): Promise<200 | 410> { return await handleDeviceChangedEventCallback(callback) default: throw new InvalidValueError( - `Event-callbacks of type "${callback.eventType}" are not supported`, + `Event-callbacks of type '${callback.eventType}' are not supported`, 400 ) } diff --git a/services/device/src/operations/callbacks/index.ts b/services/device/src/operations/callbacks/index.ts index 5dcd8a21..06e305af 100644 --- a/services/device/src/operations/callbacks/index.ts +++ b/services/device/src/operations/callbacks/index.ts @@ -21,7 +21,7 @@ export function callbackHandling(app: express.Application) { return res.status(await handleEventCallback(callback)).send() default: throw new InvalidValueError( - `Callbacks of type "${req.body.callbackType}" are not supported`, + `Callbacks of type '${req.body.callbackType}' are not supported`, 400 ) } @@ -40,12 +40,12 @@ export function callbackHandling(app: express.Application) { function getCallbackType(callback: any) { if (typeof callback.callbackType !== 'string') { throw new MalformedBodyError( - 'Property "callbackType" needs to be of type string', + "Property 'callbackType' needs to be of type string", 400 ) } if (!callback.callbackType) { - throw new MalformedBodyError('Callbacks require property "callbackType"', 400) + throw new MalformedBodyError("Callbacks require property 'callbackType'", 400) } return callback.callbackType as string } diff --git a/services/device/src/operations/devices/device/availability/post.ts b/services/device/src/operations/devices/device/availability/post.ts index 7bb254d3..63ff56e7 100644 --- a/services/device/src/operations/devices/device/availability/post.ts +++ b/services/device/src/operations/devices/device/availability/post.ts @@ -1,6 +1,6 @@ import { deviceRepository } from '../../../../database/repositories/device' import { postDevicesByDeviceIdAvailabilitySignature } from '../../../../generated/signatures' -import { applyAvailabilityRules } from '../../../../methods/availability' +import { calculateAvailability } from '../../../../methods/availability' import { sendChangedCallback } from '../../../../methods/callbacks' import { ForbiddenOperationError } from '@crosslab/service-common' @@ -16,36 +16,35 @@ const YEAR = 365 * 24 * 60 * 60 * 1000 export const postDevicesByDeviceIdAvailability: postDevicesByDeviceIdAvailabilitySignature = async (parameters, body, _user) => { console.log(`postDevicesByDeviceIdAvailability called`) - const device = await deviceRepository.findOneOrFail({ + + const deviceModel = await deviceRepository.findOneOrFail({ where: { uuid: parameters.device_id }, }) - if (device.type !== 'device') { + if (deviceModel.type !== 'device') { throw new ForbiddenOperationError( - `Can only the availability for a device of type 'device', not for type '${device.type}'` + `Can only update the availability for a device of type 'device', not for type '${deviceModel.type}'` ) } - device.availabilityRules ??= [] - device.availabilityRules.push(...(body ?? [])) + deviceModel.availabilityRules ??= [] + deviceModel.availabilityRules.push(...(body ?? [])) - device.announcedAvailability = [] const start = Date.now() const end = start + YEAR - device.announcedAvailability = applyAvailabilityRules( - device.announcedAvailability, - device.availabilityRules, + deviceModel.announcedAvailability = calculateAvailability( + deviceModel.availabilityRules, start, end ) - await deviceRepository.save(device) - await sendChangedCallback(device) + await deviceRepository.save(deviceModel) + await sendChangedCallback(deviceModel) console.log(`postDevicesByDeviceIdAvailability succeeded`) return { status: 200, - body: device.announcedAvailability, + body: deviceModel.announcedAvailability, } } diff --git a/services/device/src/operations/devices/device/delete.ts b/services/device/src/operations/devices/device/delete.ts index 44ef6a7f..6295898c 100644 --- a/services/device/src/operations/devices/device/delete.ts +++ b/services/device/src/operations/devices/device/delete.ts @@ -1,5 +1,5 @@ -import { deviceRepository } from "../../../database/repositories/device" -import { deleteDevicesByDeviceIdSignature } from "../../../generated/signatures" +import { deviceRepository } from '../../../database/repositories/device' +import { deleteDevicesByDeviceIdSignature } from '../../../generated/signatures' /** * This function implements the functionality for handling DELETE requests on /devices/{device_id} endpoint. @@ -12,15 +12,16 @@ export const deleteDevicesByDeviceId: deleteDevicesByDeviceIdSignature = async ( _user ) => { console.log(`deleteDevicesByDeviceId called`) - const device = await deviceRepository.findOneOrFail({ + + const deviceModel = await deviceRepository.findOneOrFail({ where: { uuid: parameters.device_id }, }) - await deviceRepository.remove(device) + await deviceRepository.remove(deviceModel) console.log(`deleteDevicesByDeviceId succeeded`) return { status: 204, } -} \ No newline at end of file +} diff --git a/services/device/src/operations/devices/device/get.ts b/services/device/src/operations/devices/device/get.ts index fbeb4831..4a96be39 100644 --- a/services/device/src/operations/devices/device/get.ts +++ b/services/device/src/operations/devices/device/get.ts @@ -12,14 +12,16 @@ export const getDevicesByDeviceId: getDevicesByDeviceIdSignature = async ( _user ) => { console.log(`getDevicesByDeviceId called`) - const device = await deviceRepository.findOneOrFail({ + + const deviceModel = await deviceRepository.findOneOrFail({ where: { uuid: parameters.device_id }, }) console.log(`getDevicesByDeviceId succeeded`) + return { status: 200, - body: await deviceRepository.format(device, { + body: await deviceRepository.format(deviceModel, { flatGroup: parameters.flat_group, }), } diff --git a/services/device/src/operations/devices/device/patch.ts b/services/device/src/operations/devices/device/patch.ts index 0f8e1430..99ee7a6e 100644 --- a/services/device/src/operations/devices/device/patch.ts +++ b/services/device/src/operations/devices/device/patch.ts @@ -1,7 +1,7 @@ import { deviceRepository } from '../../../database/repositories/device' import { patchDevicesByDeviceIdSignature } from '../../../generated/signatures' import { changedCallbacks, sendChangedCallback } from '../../../methods/callbacks' -import { MissingPropertyError } from '@crosslab/service-common' +import { deviceUrlFromId } from '../../../methods/urlFromId' /** * This function implements the functionality for handling PATCH requests on /devices/{device_id} endpoint. @@ -22,34 +22,22 @@ export const patchDevicesByDeviceId: patchDevicesByDeviceIdSignature = async ( where: { uuid: parameters.device_id }, }) + await deviceRepository.write(device, body ?? {}) + await deviceRepository.save(device) + + await sendChangedCallback(device) + if (parameters.changedUrl) { console.log( - `registering changed-callback for device ${device.uuid} to ${parameters.changedUrl}` + `registering changed-callback for device '${deviceUrlFromId( + device.uuid + )}' to '${parameters.changedUrl}'` ) const changedCallbackURLs = changedCallbacks.get(device.uuid) ?? [] changedCallbackURLs.push(parameters.changedUrl) changedCallbacks.set(device.uuid, changedCallbackURLs) } - if (!body || Object.keys(body).length === 0) { - console.log( - `patchDevicesByDeviceId succeeded: no changes applied due to empty body` - ) - return { - status: 200, - body: await deviceRepository.format(device), - } - } - - if (!device.type) { - throw new MissingPropertyError(`Device model is missing a type`) - } - - await deviceRepository.write(device, body) - await deviceRepository.save(device) - - await sendChangedCallback(device) - console.log(`patchDevicesByDeviceId succeeded`) return { diff --git a/services/device/src/operations/devices/device/post.ts b/services/device/src/operations/devices/device/post.ts index 428d1237..c914eb20 100644 --- a/services/device/src/operations/devices/device/post.ts +++ b/services/device/src/operations/devices/device/post.ts @@ -1,14 +1,10 @@ import { deviceRepository } from '../../../database/repositories/device' +import { concreteDeviceRepository } from '../../../database/repositories/device/concreteDevice' import { postDevicesByDeviceIdSignature } from '../../../generated/signatures' -import { ConcreteDevice } from '../../../generated/types' import { apiClient } from '../../../globals' import { changedCallbacks } from '../../../methods/callbacks' import { deviceUrlFromId } from '../../../methods/urlFromId' -import { - ForbiddenOperationError, - InvalidValueError, - MissingPropertyError, -} from '@crosslab/service-common' +import { ForbiddenOperationError } from '@crosslab/service-common' /** * This function implements the functionality for handling POST requests on /devices/{device_id} endpoint. @@ -22,64 +18,49 @@ export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( user ) => { console.log(`postDevicesByDeviceId called`) - const instantiableDevice = await deviceRepository.findOneOrFail({ + + const instantiableDeviceModel = await deviceRepository.findOneOrFail({ where: { uuid: parameters.device_id }, }) if ( - instantiableDevice.type !== 'cloud instantiable' && - instantiableDevice.type !== 'edge instantiable' + instantiableDeviceModel.type !== 'cloud instantiable' && + instantiableDeviceModel.type !== 'edge instantiable' ) throw new ForbiddenOperationError( `Cannot create new instance of device ${deviceUrlFromId( - instantiableDevice.uuid - )} since it has type "${instantiableDevice.type}"`, + instantiableDeviceModel.uuid + )} since it has type "${instantiableDeviceModel.type}"`, 400 ) - const concreteDevice: ConcreteDevice = { + const concreteDeviceModel = await concreteDeviceRepository.create({ services: [], - ...(await deviceRepository.format(instantiableDevice)), + ...(await deviceRepository.format(instantiableDeviceModel)), type: 'device', announcedAvailability: [{ available: true }], - } - const concreteDeviceModel = await deviceRepository.create(concreteDevice) - - if (concreteDeviceModel.type !== 'device') { - throw new InvalidValueError( - `Created instance does not have type 'device', but has type ${concreteDeviceModel.type}` - ) - } - + }) concreteDeviceModel.owner = user.JWT?.url - await deviceRepository.save(concreteDeviceModel) if (parameters.changedUrl) { console.log( - `registering changed-callback for device ${concreteDevice.uuid} to ${parameters.changedUrl}` + `registering changed-callback for device '${deviceUrlFromId( + concreteDeviceModel.uuid + )}' to '${parameters.changedUrl}'` ) const changedCallbackURLs = changedCallbacks.get(concreteDeviceModel.uuid) ?? [] changedCallbackURLs.push(parameters.changedUrl) changedCallbacks.set(concreteDeviceModel.uuid, changedCallbackURLs) } - const instance = await deviceRepository.format(concreteDeviceModel) - if (!instance.url) - throw new MissingPropertyError( - 'Created instance of device does not have an url', - 500 - ) - if (instance.type !== 'device') { - throw new InvalidValueError( - `Created instance does not have type 'device', but has type ${concreteDeviceModel.type}` - ) - } + const instance = await concreteDeviceRepository.format(concreteDeviceModel) const deviceToken = await apiClient.createDeviceAuthenticationToken(instance.url) // TODO: error handling - instantiableDevice.instances ??= [] - instantiableDevice.instances.push(concreteDeviceModel) + instantiableDeviceModel.instances ??= [] + instantiableDeviceModel.instances.push(concreteDeviceModel) - await deviceRepository.save(instantiableDevice) + await deviceRepository.save(concreteDeviceModel) + await deviceRepository.save(instantiableDeviceModel) console.log(`postDevicesByDeviceId succeeded`) diff --git a/services/device/src/operations/devices/device/signaling/post.ts b/services/device/src/operations/devices/device/signaling/post.ts index 4e51485f..3a360820 100644 --- a/services/device/src/operations/devices/device/signaling/post.ts +++ b/services/device/src/operations/devices/device/signaling/post.ts @@ -5,7 +5,6 @@ import { apiClient } from '../../../../globals' import { deviceUrlFromId } from '../../../../methods/urlFromId' import { ForbiddenOperationError, - MissingPropertyError, UnrelatedPeerconnectionError, MissingEntityError, } from '@crosslab/service-common' @@ -23,14 +22,14 @@ export const postDevicesByDeviceIdSignaling: postDevicesByDeviceIdSignalingSigna console.log(`postDevicesByDeviceIdSignaling called`) // Get device - const device = await deviceRepository.findOneOrFail({ + const deviceModel = await deviceRepository.findOneOrFail({ where: { uuid: parameters.device_id }, }) // Make sure device is a concrete device - if (device.type !== 'device') + if (deviceModel.type !== 'device') throw new ForbiddenOperationError( - `Cannot send signaling message to device with type ${device.type}`, + `Cannot send signaling message to device with type '${deviceModel.type}'`, 400 ) @@ -38,17 +37,12 @@ export const postDevicesByDeviceIdSignaling: postDevicesByDeviceIdSignalingSigna const peerconnection = await apiClient.getPeerconnection( parameters.peerconnection_url ) - if (!peerconnection.devices) - throw new MissingPropertyError( - `Peerconnection does not have any devices`, - 404 - ) const deviceA = peerconnection.devices[0] const deviceB = peerconnection.devices[1] if ( - !(deviceA.url === deviceUrlFromId(device.uuid)) && - !(deviceB.url === deviceUrlFromId(device.uuid)) + !(deviceA.url === deviceUrlFromId(deviceModel.uuid)) && + !(deviceB.url === deviceUrlFromId(deviceModel.uuid)) ) { throw new UnrelatedPeerconnectionError( `Device is not part of the peerconnection`, @@ -56,15 +50,15 @@ export const postDevicesByDeviceIdSignaling: postDevicesByDeviceIdSignalingSigna ) } - const ws = connectedDevices.get(parameters.device_id) + const webSocket = connectedDevices.get(parameters.device_id) - if (!ws) + if (!webSocket) throw new MissingEntityError( `Could not find websocket connection for device ${parameters.device_id}`, 404 ) - ws.send(JSON.stringify(body)) + webSocket.send(JSON.stringify(body)) console.log(`postDevicesByDeviceIdSignaling succeeded`) diff --git a/services/device/src/operations/devices/device/websocket/post.ts b/services/device/src/operations/devices/device/websocket/post.ts index f9d08fb9..509518ae 100644 --- a/services/device/src/operations/devices/device/websocket/post.ts +++ b/services/device/src/operations/devices/device/websocket/post.ts @@ -1,8 +1,7 @@ -import { MissingEntityError } from "@crosslab/service-common" -import { randomUUID } from "crypto" -import { AppDataSource } from "../../../../database/dataSource" -import { ConcreteDeviceModel } from "../../../../database/model" -import { postDevicesByDeviceIdWebsocketSignature } from "../../../../generated/signatures" +import { AppDataSource } from '../../../../database/dataSource' +import { ConcreteDeviceModel } from '../../../../database/model' +import { postDevicesByDeviceIdWebsocketSignature } from '../../../../generated/signatures' +import { randomUUID } from 'crypto' /** * This function implements the functionality for handling POST requests on /devices/{device_id}/token endpoint. @@ -12,28 +11,25 @@ import { postDevicesByDeviceIdWebsocketSignature } from "../../../../generated/s */ export const postDevicesByDeviceIdWebsocket: postDevicesByDeviceIdWebsocketSignature = async (parameters, _user) => { - console.log(`postDevicesByDeviceIdToken called`) - const deviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) - const device = await deviceRepository.findOneBy({ uuid: parameters.device_id }) + console.log(`postDevicesByDeviceIdWebsocket called`) - if (!device) - throw new MissingEntityError( - `Could not find device ${parameters.device_id}`, - 404 - ) + const deviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) + const deviceModel = await deviceRepository.findOneByOrFail({ + uuid: parameters.device_id, + }) - device.token = randomUUID() - await deviceRepository.save(device) + deviceModel.token = randomUUID() + await deviceRepository.save(deviceModel) setTimeout(async () => { - device.token = undefined - await deviceRepository.save(device) + deviceModel.token = undefined + await deviceRepository.save(deviceModel) }, 300000) - console.log(`postDevicesByDeviceIdToken succeeded`) + console.log(`postDevicesByDeviceIdWebsocket succeeded`) return { status: 200, - body: device.token, + body: deviceModel.token, } - } \ No newline at end of file + } diff --git a/services/device/src/operations/devices/get.ts b/services/device/src/operations/devices/get.ts index 64da1d00..cd77eb64 100644 --- a/services/device/src/operations/devices/get.ts +++ b/services/device/src/operations/devices/get.ts @@ -7,14 +7,17 @@ import { getDevicesSignature } from '../../generated/signatures' */ export const getDevices: getDevicesSignature = async (_user) => { console.log(`getDevices called`) - const devices = await deviceRepository.find() + + const deviceModels = await deviceRepository.find() console.log(`getDevices succeeded`) return { status: 200, body: await Promise.all( - devices.map((device) => deviceRepository.format(device, { overview: true })) + deviceModels.map((device) => + deviceRepository.format(device, { overview: true }) + ) ), } } diff --git a/services/device/src/operations/devices/post.ts b/services/device/src/operations/devices/post.ts index f0170fbf..fa73c79f 100644 --- a/services/device/src/operations/devices/post.ts +++ b/services/device/src/operations/devices/post.ts @@ -11,23 +11,23 @@ import { changedCallbacks } from '../../methods/callbacks' export const postDevices: postDevicesSignature = async (parameters, body, user) => { console.log(`postDevices called`) - const device = await deviceRepository.create(body) - device.owner = user.JWT?.url - await deviceRepository.save(device) + const deviceModel = await deviceRepository.create(body) + deviceModel.owner = user.JWT?.url + await deviceRepository.save(deviceModel) if (parameters.changedUrl) { console.log( - `registering changed-callback for device ${device.uuid} to ${parameters.changedUrl}` + `registering changed-callback for device ${deviceModel.uuid} to '${parameters.changedUrl}'` ) - const changedCallbackURLs = changedCallbacks.get(device.uuid) ?? [] + const changedCallbackURLs = changedCallbacks.get(deviceModel.uuid) ?? [] changedCallbackURLs.push(parameters.changedUrl) - changedCallbacks.set(device.uuid, changedCallbackURLs) + changedCallbacks.set(deviceModel.uuid, changedCallbackURLs) } console.log(`postDevices succeeded`) return { status: 201, - body: await deviceRepository.format(device), + body: await deviceRepository.format(deviceModel), } } diff --git a/services/device/src/operations/devices/websocket/index.ts b/services/device/src/operations/devices/websocket/index.ts index 9634e842..bfb9da6a 100644 --- a/services/device/src/operations/devices/websocket/index.ts +++ b/services/device/src/operations/devices/websocket/index.ts @@ -1,16 +1,23 @@ -import { AppDataSource } from '../../../database/dataSource' -import { ConcreteDeviceModel } from '../../../database/model' +import { concreteDeviceRepository } from '../../../database/repositories/device/concreteDevice' import { isMessage, isAuthenticationMessage, AuthenticationMessage, } from '../../../generated/types' import { sendChangedCallback } from '../../../methods/callbacks' +import { deviceUrlFromId } from '../../../methods/urlFromId' import { handleDeviceMessage } from './messageHandling' import WebSocket from 'ws' export const connectedDevices = new Map() +class WebSocketConnectionError extends Error { + constructor(message: string) { + super(message) + this.name = 'WebSocketConnectionError' + } +} + /** * This function adds the /devices/ws endpoint, including its functionality, to an express application. * @param app The express application to add the /devices/ws endpoint to. @@ -20,85 +27,96 @@ export function websocketHandling(app: Express.Application) { app.ws('/devices/websocket', (ws) => { // authenticate and start heartbeat ws.once('message', async (data) => { - // device authentication and connection - const deviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) - const message = JSON.parse(data.toString('utf8')) + try { + // device authentication and connection + const message = JSON.parse(data.toString('utf8')) - if (!(isMessage(message) && isAuthenticationMessage(message))) { - ws.close(1002, 'Received message is not an authentication message') - return - } + if (!(isMessage(message) && isAuthenticationMessage(message))) { + return ws.close( + 1002, + 'Received message is not an authentication message' + ) + } - if (!message.token) { - ws.close( - 1002, - 'Authentication message does not contain a valid websocket token' - ) - } + if (!message.token) { + return ws.close( + 1002, + 'Authentication message does not contain a valid websocket token' + ) + } - const device = await deviceRepository.findOne({ - where: { token: message.token }, - }) - if (!device) { - ws.close(1002, 'No device found with matching websocket token') - return - } + const deviceModel = await concreteDeviceRepository.findOne({ + where: { token: message.token }, + }) + if (!deviceModel) { + return ws.close(1002, 'No device found with matching websocket token') + } - if (device.token != message.token) { - ws.close(1002, 'Provided token does not match the token of the device') - return - } + deviceModel.connected = true + connectedDevices.set(deviceModel.uuid, ws) + await concreteDeviceRepository.save(deviceModel) + await sendChangedCallback(deviceModel) + console.log(`device '${deviceUrlFromId(deviceModel.uuid)}' connected`) - device.connected = true - connectedDevices.set(device.uuid, ws) - await deviceRepository.save(device) - await sendChangedCallback(device) - console.log(`device ${device.uuid} connected`) + // TODO: find out if this is really how it was intended + ws.send( + JSON.stringify({ + messageType: 'authenticate', + authenticated: true, + }) + ) - ws.send( - JSON.stringify({ - messageType: 'authenticate', - authenticated: true, + // heartbeat implementation + let isAlive = true + ws.on('pong', () => { + isAlive = true }) - ) + const interval = setInterval(async function ping() { + try { + if (isAlive === false) { + deviceModel.connected = false + await concreteDeviceRepository.save(deviceModel) + await sendChangedCallback(deviceModel) + connectedDevices.delete(deviceModel.uuid) + clearInterval(interval) + return ws.terminate() + } + isAlive = false + ws.ping() + } catch (error) { + console.error(error) + } + }, 30000) - // heartbeat implementation - let isAlive = true - ws.on('pong', () => { - isAlive = true - }) - const interval = setInterval(async function ping() { - if (isAlive === false) { - device.connected = false - await deviceRepository.save(device) - await sendChangedCallback(device) - connectedDevices.delete(device.uuid) + // close handler: stop heartbeat and disconnect device + ws.on('close', async (code, reason) => { clearInterval(interval) - return ws.terminate() - } - isAlive = false - ws.ping() - }, 30000) + connectedDevices.delete(deviceModel.uuid) - // close handler: stop heartbeat and disconnect device - ws.on('close', async (code, reason) => { - clearInterval(interval) - connectedDevices.delete(device.uuid) - - if (code === 1002) { - console.error(`WebSocketConnctionError "${reason}"`) - } - }) + if (code === 1002) { + console.error( + new WebSocketConnectionError(reason.toString('utf-8')) + ) + } + }) - // message handler: handle incoming messages from devices - ws.on('message', async (data) => { - const message = JSON.parse(data.toString('utf8')) - if (!isMessage(message)) { - ws.close(1002, 'Malformed Message') - return - } - handleDeviceMessage(device, message) - }) + // message handler: handle incoming messages from devices + ws.on('message', async (data) => { + try { + const message = JSON.parse(data.toString('utf-8')) + if (!isMessage(message)) { + ws.close(1002, 'Malformed Message') + return + } + await handleDeviceMessage(deviceModel, message) + } catch (error) { + console.error(error) + } + }) + } catch (error) { + console.error(error) + return ws.close(1002, 'Something went wrong during authentication') + } }) }) } diff --git a/services/device/src/operations/devices/websocket/messageHandling.ts b/services/device/src/operations/devices/websocket/messageHandling.ts index ab0c640c..e70cf124 100644 --- a/services/device/src/operations/devices/websocket/messageHandling.ts +++ b/services/device/src/operations/devices/websocket/messageHandling.ts @@ -1,63 +1,70 @@ import { ConcreteDeviceModel } from '../../../database/model' -import { SignalingMessage, Message, isSignalingMessage } from '../../../generated/types' +import { + SignalingMessage, + Message, + isSignalingMessage, + isConnectionStateChangedMessage, + ConnectionStateChangedMessage, +} from '../../../generated/types' import { apiClient } from '../../../globals' import { deviceUrlFromId } from '../../../methods/urlFromId' -import { - MissingPropertyError, - UnrelatedPeerconnectionError, -} from '@crosslab/service-common' +import { UnrelatedPeerconnectionError } from '@crosslab/service-common' /** * This function handles a message for a device. - * @param device The device for which to handle the message. + * @param deviceModel The device for which to handle the message. * @param message The message to be handled. */ -export function handleDeviceMessage(device: ConcreteDeviceModel, message: Message) { +export async function handleDeviceMessage( + deviceModel: ConcreteDeviceModel, + message: Message +) { if (isSignalingMessage(message)) { - handleSignalingMessage(device, message) + await handleSignalingMessage(deviceModel, message) + } else if (isConnectionStateChangedMessage(message)) { + await handleConnectionStateChangedMessage(deviceModel, message) } } /** * This function handles a signaling message for a device. - * @param device The device for which to handle the signaling message. + * @param deviceModel The device for which to handle the signaling message. * @param message The signaling message to be handled. */ async function handleSignalingMessage( - device: ConcreteDeviceModel, + deviceModel: ConcreteDeviceModel, message: SignalingMessage ) { const peerconnection = await apiClient.getPeerconnection(message.connectionUrl) - if (!peerconnection.devices) - throw new MissingPropertyError('Peerconnection has no devices') - const deviceA = peerconnection.devices[0] const deviceB = peerconnection.devices[1] - let peerDeviceUrl - if (deviceA.url === deviceUrlFromId(device.uuid)) { - peerDeviceUrl = deviceB.url - } else if (deviceB.url === deviceUrlFromId(device.uuid)) { - peerDeviceUrl = deviceA.url - } else { + let peerDeviceUrl: string | undefined = undefined + if (deviceA.url === deviceUrlFromId(deviceModel.uuid)) peerDeviceUrl = deviceB.url + if (deviceB.url === deviceUrlFromId(deviceModel.uuid)) peerDeviceUrl = deviceA.url + if (!peerDeviceUrl) { throw new UnrelatedPeerconnectionError( - 'Device is not taking part in peerconnection.' + 'Device is not taking part in peerconnection.', + 400 ) } - if (!peerDeviceUrl) throw new MissingPropertyError('Peer device is missing its url') + await apiClient.sendSignalingMessage(peerDeviceUrl, message, message.connectionUrl) +} - try { - await apiClient.sendSignalingMessage( - peerDeviceUrl, - message, - message.connectionUrl - ) - } catch (error) { - console.error( - 'Something went wrong while trying to send the signaling message:', - error - ) - } +/** + * This function handles a connection-state-changed message for a device. + * @param deviceModel The device for which the connection state changed + * @param message The connection-state-changed message. + */ +async function handleConnectionStateChangedMessage( + deviceModel: ConcreteDeviceModel, + message: ConnectionStateChangedMessage +) { + await apiClient.patchPeerconnectionDeviceStatus( + message.connectionUrl, + { status: message.status }, + deviceUrlFromId(deviceModel.uuid) + ) } diff --git a/services/device/src/operations/peerconnections/get.ts b/services/device/src/operations/peerconnections/get.ts index eaffdb69..1d1237c0 100644 --- a/services/device/src/operations/peerconnections/get.ts +++ b/services/device/src/operations/peerconnections/get.ts @@ -7,12 +7,13 @@ import { getPeerconnectionsSignature } from '../../generated/signatures' */ export const getPeerconnections: getPeerconnectionsSignature = async (_user) => { console.log(`getPeerconnections called`) - const peerconnections = await peerconnectionRepository.find() + + const peerconnectionModels = await peerconnectionRepository.find() console.log(`getPeerconnections succeeded`) return { status: 200, - body: peerconnections.map(peerconnectionRepository.formatOverview), + body: peerconnectionModels.map(peerconnectionRepository.formatOverview), } } diff --git a/services/device/src/operations/peerconnections/peerconnection/delete.ts b/services/device/src/operations/peerconnections/peerconnection/delete.ts index 81f316c4..abbe53db 100644 --- a/services/device/src/operations/peerconnections/peerconnection/delete.ts +++ b/services/device/src/operations/peerconnections/peerconnection/delete.ts @@ -2,7 +2,7 @@ import { peerconnectionRepository } from '../../../database/repositories/peercon import { deletePeerconnectionsByPeerconnectionIdSignature } from '../../../generated/signatures' import { ClosePeerconnectionMessage } from '../../../generated/types' import { apiClient } from '../../../globals' -import { sendClosedCallback } from '../../../methods/callbacks' +import { sendClosedCallback, sendStatusChangedCallback } from '../../../methods/callbacks' import { peerconnectionUrlFromId } from '../../../methods/urlFromId' /** @@ -14,36 +14,44 @@ export const deletePeerconnectionsByPeerconnectionId: deletePeerconnectionsByPee async (parameters, _user) => { console.log(`deletePeerconnectionsByPeerconnectionId called`) - const peerconnection = await peerconnectionRepository.findOneOrFail({ + const peerconnectionModel = await peerconnectionRepository.findOne({ where: { uuid: parameters.peerconnection_id }, }) - await peerconnectionRepository.remove(peerconnection) + if (!peerconnectionModel) + return { + status: 204, + } - if (peerconnection.status === 'connected') { + if ( + peerconnectionModel.status === 'connecting' || + peerconnectionModel.status === 'connected' || + peerconnectionModel.status === 'disconnected' + ) { const closePeerconnectionMessage: ClosePeerconnectionMessage = { messageType: 'command', command: 'closePeerconnection', - connectionUrl: peerconnectionUrlFromId(peerconnection.uuid), + connectionUrl: peerconnectionUrlFromId(peerconnectionModel.uuid), } - if (peerconnection.deviceA.url && peerconnection.deviceB.url) { - await apiClient.sendSignalingMessage( - peerconnection.deviceA.url, - closePeerconnectionMessage, - peerconnectionUrlFromId(peerconnection.uuid) - ) - - await apiClient.sendSignalingMessage( - peerconnection.deviceB.url, - closePeerconnectionMessage, - peerconnectionUrlFromId(peerconnection.uuid) - ) - } + await apiClient.sendSignalingMessage( + peerconnectionModel.deviceA.url, + closePeerconnectionMessage, + peerconnectionUrlFromId(peerconnectionModel.uuid) + ) - await sendClosedCallback(peerconnection) + await apiClient.sendSignalingMessage( + peerconnectionModel.deviceB.url, + closePeerconnectionMessage, + peerconnectionUrlFromId(peerconnectionModel.uuid) + ) + + await sendClosedCallback(peerconnectionModel) + await sendStatusChangedCallback(peerconnectionModel) } + await peerconnectionRepository.remove(peerconnectionModel) + console.log(`deletePeerconnectionsByPeerconnectionId succeeded`) return { diff --git a/services/device/src/operations/peerconnections/peerconnection/device_status/index.ts b/services/device/src/operations/peerconnections/peerconnection/device_status/index.ts new file mode 100644 index 00000000..112db4e9 --- /dev/null +++ b/services/device/src/operations/peerconnections/peerconnection/device_status/index.ts @@ -0,0 +1 @@ +export * from './patch' diff --git a/services/device/src/operations/peerconnections/peerconnection/device_status/patch.ts b/services/device/src/operations/peerconnections/peerconnection/device_status/patch.ts new file mode 100644 index 00000000..f798c6b1 --- /dev/null +++ b/services/device/src/operations/peerconnections/peerconnection/device_status/patch.ts @@ -0,0 +1,77 @@ +import { peerconnectionRepository } from '../../../../database/repositories/peerconnection' +import { patchPeerconnectionsByPeerconnectionIdDeviceStatusSignature } from '../../../../generated/signatures' +import { peerconnectionUrlFromId } from '../../../../methods/urlFromId' +import { sendStatusChangedCallback } from '../../../callbacks' +import { UnrelatedPeerconnectionError } from '@crosslab/service-common' + +/** + * This function implements the functionality for handling GET requests on /peerconnections/{peerconnection_id} endpoint. + * @param parameters The parameters of the request. + * @param _user The user submitting the request. + */ +export const patchPeerconnectionsByPeerconnectionIdDeviceStatus: patchPeerconnectionsByPeerconnectionIdDeviceStatusSignature = + async (parameters, body, _user) => { + console.log(`patchPeerconnectionsByPeerconnectionIdDeviceStatus called`) + + const peerconnectionModel = await peerconnectionRepository.findOneOrFail({ + where: { uuid: parameters.peerconnection_id }, + }) + + if ( + peerconnectionModel.deviceA.url !== parameters.device_url && + peerconnectionModel.deviceB.url !== parameters.device_url + ) { + throw new UnrelatedPeerconnectionError( + `Device '${ + parameters.device_url + }' is not taking part in peerconnection '${peerconnectionUrlFromId( + peerconnectionModel.uuid + )}'`, + 400 + ) + } + + if (peerconnectionModel.deviceA.url === parameters.device_url) + peerconnectionModel.deviceA.status = body.status + + if (peerconnectionModel.deviceB.url === parameters.device_url) + peerconnectionModel.deviceB.status = body.status + + const oldStatus = peerconnectionModel.status + + if ( + peerconnectionModel.deviceA.status === 'failed' || + peerconnectionModel.deviceB.status === 'failed' + ) { + peerconnectionModel.status = 'failed' + } else if ( + peerconnectionModel.deviceA.status === 'closed' || + peerconnectionModel.deviceB.status === 'closed' + ) { + peerconnectionModel.status = 'closed' + } else if ( + peerconnectionModel.deviceA.status === 'disconnected' || + peerconnectionModel.deviceB.status === 'disconnected' + ) { + peerconnectionModel.status = 'disconnected' + } else if ( + peerconnectionModel.deviceA.status === 'connecting' && + peerconnectionModel.deviceB.status === 'connecting' + ) { + peerconnectionModel.status = 'connecting' + } else if ( + peerconnectionModel.deviceA.status === 'connected' && + peerconnectionModel.deviceB.status === 'connected' + ) { + peerconnectionModel.status = 'connected' + } + + if (peerconnectionModel.status !== oldStatus) + await sendStatusChangedCallback(peerconnectionModel) + + console.log(`patchPeerconnectionsByPeerconnectionIdDeviceStatus succeeded`) + + return { + status: 201, + } + } diff --git a/services/device/src/operations/peerconnections/peerconnection/get.ts b/services/device/src/operations/peerconnections/peerconnection/get.ts index c8c932ca..e16390a3 100644 --- a/services/device/src/operations/peerconnections/peerconnection/get.ts +++ b/services/device/src/operations/peerconnections/peerconnection/get.ts @@ -10,7 +10,7 @@ export const getPeerconnectionsByPeerconnectionId: getPeerconnectionsByPeerconne async (parameters, _user) => { console.log(`getPeerconnectionsByPeerconnectionId called`) - const peerconnection = await peerconnectionRepository.findOneOrFail({ + const peerconnectionModel = await peerconnectionRepository.findOneOrFail({ where: { uuid: parameters.peerconnection_id }, }) @@ -18,6 +18,6 @@ export const getPeerconnectionsByPeerconnectionId: getPeerconnectionsByPeerconne return { status: 200, - body: await peerconnectionRepository.format(peerconnection), + body: await peerconnectionRepository.format(peerconnectionModel), } } diff --git a/services/device/src/operations/peerconnections/peerconnection/index.ts b/services/device/src/operations/peerconnections/peerconnection/index.ts index 4109217b..7f70059f 100644 --- a/services/device/src/operations/peerconnections/peerconnection/index.ts +++ b/services/device/src/operations/peerconnections/peerconnection/index.ts @@ -1,2 +1,3 @@ export * from './delete' export * from './get' +export * from './device_status' diff --git a/services/device/src/operations/peerconnections/post.ts b/services/device/src/operations/peerconnections/post.ts index 9549c69a..0b8d8781 100644 --- a/services/device/src/operations/peerconnections/post.ts +++ b/services/device/src/operations/peerconnections/post.ts @@ -8,11 +8,7 @@ import { statusChangedCallbacks, } from '../../methods/callbacks' import { signalingQueue } from '../../methods/signaling' -import { - MissingEntityError, - InvalidValueError, - MissingPropertyError, -} from '@crosslab/service-common' +import { InvalidValueError } from '@crosslab/service-common' /** * This function implements the functionality for handling POST requests on /peerconnections endpoint. @@ -27,34 +23,23 @@ export const postPeerconnections: postPeerconnectionsSignature = async ( ) => { console.log(`postPeerconnections called`) - const peerconnection = await peerconnectionRepository.create(body) - - if (!peerconnection.deviceA.url || !peerconnection.deviceB.url) { - throw new MissingEntityError(`One of the participating devices has no url`, 404) - } + const peerconnectionModel = await peerconnectionRepository.create(body) - await peerconnectionRepository.save(peerconnection) + await peerconnectionRepository.save(peerconnectionModel) - const deviceA = await apiClient.getDevice(peerconnection.deviceA.url) - const deviceB = await apiClient.getDevice(peerconnection.deviceB.url) + const deviceA = await apiClient.getDevice(peerconnectionModel.deviceA.url) + const deviceB = await apiClient.getDevice(peerconnectionModel.deviceB.url) if (deviceA.type !== 'device' || deviceB.type !== 'device') { throw new InvalidValueError( - `Cannot establish a peerconnection between devices of type "${deviceA.type}" and "${deviceB.type}"`, + `Cannot establish a peerconnection between devices of type '${deviceA.type}' and '${deviceB.type}'`, 400 ) } - if (!deviceA.url || !deviceB.url) { - throw new MissingPropertyError( - `One of the resolved devices does not have an url`, - 500 - ) // NOTE: error code - } - if (deviceA.connected && deviceB.connected) { // peerconnection can be started directly - signalingQueue.addPeerconnection(peerconnection) + signalingQueue.addPeerconnection(peerconnectionModel) } else { // need to wait for devices to connect // register changed callbacks for devices to get notified when they connect @@ -72,48 +57,50 @@ export const postPeerconnections: postPeerconnectionsSignature = async ( // check that devices still have the correct type if (n_deviceA.type !== 'device' || n_deviceB.type !== 'device') { throw new InvalidValueError( - `The type of device ${ - deviceA.type !== 'device' ? deviceA.url : deviceB.url - } is not "device" anymore`, + `Cannot establish a peerconnection between devices of type '${deviceA.type}' and '${deviceB.type}'`, 400 ) } // set timeout for checking if devices are connected timeoutMap.set( - peerconnection.uuid, + peerconnectionModel.uuid, setTimeout(async () => { - console.log('devices did not connect') - peerconnection.status = 'failed' - await peerconnectionRepository.save(peerconnection) - await sendStatusChangedCallback(peerconnection) + try { + console.log('devices did not connect') + peerconnectionModel.status = 'failed' + await peerconnectionRepository.save(peerconnectionModel) + await sendStatusChangedCallback(peerconnectionModel) + } catch (error) { + console.error(error) + } }, 30000) ) } if (parameters.closedUrl) { console.log( - `postPeerconnections: registering closed-callback for ${parameters.closedUrl}` + `postPeerconnections: registering closed-callback for '${parameters.closedUrl}'` ) - const closedCallbackURLs = closedCallbacks.get(peerconnection.uuid) ?? [] + const closedCallbackURLs = closedCallbacks.get(peerconnectionModel.uuid) ?? [] closedCallbackURLs.push(parameters.closedUrl) - closedCallbacks.set(peerconnection.uuid, closedCallbackURLs) + closedCallbacks.set(peerconnectionModel.uuid, closedCallbackURLs) } if (parameters.statusChangedUrl) { console.log( - `postPeerconnections: registering status-changed-callback for ${parameters.statusChangedUrl}` + `postPeerconnections: registering status-changed-callback for '${parameters.statusChangedUrl}'` ) const statusChangedCallbackURLs = - statusChangedCallbacks.get(peerconnection.uuid) ?? [] + statusChangedCallbacks.get(peerconnectionModel.uuid) ?? [] statusChangedCallbackURLs.push(parameters.statusChangedUrl) - statusChangedCallbacks.set(peerconnection.uuid, statusChangedCallbackURLs) + statusChangedCallbacks.set(peerconnectionModel.uuid, statusChangedCallbackURLs) } console.log(`postPeerconnections succeeded`) return { - status: peerconnection.status === 'connected' ? 201 : 202, - body: await peerconnectionRepository.format(peerconnection), + status: peerconnectionModel.status === 'connected' ? 201 : 202, + body: await peerconnectionRepository.format(peerconnectionModel), } } diff --git a/services/device/tsconfig.build.json b/services/device/tsconfig.build.json new file mode 100644 index 00000000..5fa0b0e0 --- /dev/null +++ b/services/device/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "src" + }, + "exclude": [ + "test/**/*.spec.ts" + ] +} \ No newline at end of file From f27daa6936caeaa7f245a8d1aef07b8ecc631399 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Thu, 23 Mar 2023 10:51:37 +0100 Subject: [PATCH 11/33] small bugfix --- services/device/src/database/model.ts | 2 +- .../device/src/database/repositories/device/concreteDevice.ts | 1 + services/device/src/database/repositories/device/deviceGroup.ts | 1 + .../database/repositories/device/instantiableBrowserDevice.ts | 1 + .../src/database/repositories/device/instantiableCloudDevice.ts | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/services/device/src/database/model.ts b/services/device/src/database/model.ts index 24627142..e8598e63 100644 --- a/services/device/src/database/model.ts +++ b/services/device/src/database/model.ts @@ -112,7 +112,7 @@ export abstract class PeerconnectionModel { uuid!: string @Column() type!: 'local' | 'webrtc' - @Column() + @Column('varchar') status!: ConnectionStatus @Column('simple-json') deviceA!: ConfiguredDeviceReference & { status: ConnectionStatus } diff --git a/services/device/src/database/repositories/device/concreteDevice.ts b/services/device/src/database/repositories/device/concreteDevice.ts index 24d0a1bd..43c3ebf3 100644 --- a/services/device/src/database/repositories/device/concreteDevice.ts +++ b/services/device/src/database/repositories/device/concreteDevice.ts @@ -25,6 +25,7 @@ export class ConcreteDeviceRepository extends AbstractRepository< async create(data?: ConcreteDeviceInit<'request'>): Promise { const model = await super.create(data) + model.type = 'device' return model } diff --git a/services/device/src/database/repositories/device/deviceGroup.ts b/services/device/src/database/repositories/device/deviceGroup.ts index 4be7b99b..7ccaae2c 100644 --- a/services/device/src/database/repositories/device/deviceGroup.ts +++ b/services/device/src/database/repositories/device/deviceGroup.ts @@ -28,6 +28,7 @@ export class DeviceGroupRepository extends AbstractRepository< async create(data?: DeviceGroupInit<'request'>): Promise { const model = await super.create(data) + model.type = 'group' return model } diff --git a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts index 93865a1b..00a1ef35 100644 --- a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts +++ b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts @@ -27,6 +27,7 @@ export class InstantiableBrowserDeviceRepository extends AbstractRepository< data?: InstantiableBrowserDeviceInit<'request'> ): Promise { const model = await super.create(data) + model.type = 'edge instantiable' return model } diff --git a/services/device/src/database/repositories/device/instantiableCloudDevice.ts b/services/device/src/database/repositories/device/instantiableCloudDevice.ts index 140fbe45..a5282af9 100644 --- a/services/device/src/database/repositories/device/instantiableCloudDevice.ts +++ b/services/device/src/database/repositories/device/instantiableCloudDevice.ts @@ -27,6 +27,7 @@ export class InstantiableCloudDeviceRepository extends AbstractRepository< data?: InstantiableCloudDeviceInit<'request'> ): Promise { const model = await super.create(data) + model.type = 'cloud instantiable' return model } From 13db4ad2d371beab092620880dcdd099c83a0e7f Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 27 Mar 2023 09:50:11 +0200 Subject: [PATCH 12/33] Restructure TypeScript-Plugin --- .../typescript/filters/common/addProperty.ts | 10 + .../typescript/filters/common/append.ts | 10 + .../typescript/filters/common/attribute.ts | 16 + .../typescript/filters/common/cap.ts | 15 + .../typescript/filters/common/clone.ts | 14 + .../typescript/filters/common/delete.ts | 8 + .../typescript/filters/common/endsWith.ts | 17 + .../typescript/filters/common/flatten.ts | 20 + .../typescript/filters/common/includes.ts | 10 + .../typescript/filters/common/index.ts | 34 + .../filters/common/sortByAttribute.ts | 33 + .../typescript/filters/common/split.ts | 21 + .../typescript/filters/common/startsWith.ts | 17 + .../typescript/filters/common/stringify.ts | 16 + .../typescript/filters/common/toStrings.ts | 16 + .../typescript/filters/common/unique.ts | 15 + .../filters/format/formatExpressPath.ts | 7 + .../typescript/filters/format/formatName.ts | 7 + .../filters/format/formatOperation.ts | 7 + .../typescript/filters/format/index.ts | 12 + .../typescript/filters/format/prettier.ts | 16 + .../generateBasicValidationFunctions.ts} | 11 +- .../generate/generateInvalidSchemas.ts | 7 + .../generateSchemasWithoutUnrequired.ts | 7 + .../typescript/filters/generate/index.ts | 10 + .../filters/helper/getInvalidStatusCode.ts | 40 + .../helper/getPossibleScopeCombinations.ts | 31 + .../typescript/filters/helper/index.ts | 8 + .../typescript/filters/index.ts | 16 + .../typescript/filters/resolve/index.ts | 5 + .../filters/resolve/resolveOperations.ts | 8 + .../filters/resolve/resolveSchemas.ts | 9 + .../filters/typing/destructureSchema.ts | 15 + .../typescript/filters/typing/index.ts | 14 + .../filters/typing/inlineTypeDeclaration.ts | 18 + .../filters/typing/standaloneTypings.ts | 70 ++ .../filters/typing/typeDeclaration.ts | 24 + .../filters/typing/typeDependencies.ts | 22 + .../typescript/format.ts | 0 .../src/filterCollections/typescript/index.ts | 10 + .../typescript/resolve/removeReadWriteOnly.ts | 114 +++ .../typescript/resolve/resolveOperations.ts | 151 ++++ .../typescript/resolve/resolveSchemas.ts | 258 +++++++ .../schema-generation/invalidSchemas.ts | 203 +++++ .../schema-generation/validSchemas.ts | 0 .../schema-generation/withoutUnrequired.ts | 62 ++ .../typescript/schemas/userType.ts | 0 .../src/filterCollections/typescript/types.ts | 78 ++ .../typescript/typings/destructure.ts | 58 ++ .../typescript/typings/keywords/allOf.ts | 24 + .../typescript/typings/keywords/anyOf.ts | 21 + .../typescript/typings/keywords/const.ts | 17 + .../typescript/typings/keywords/enum.ts | 10 + .../typescript/typings/keywords/oneOf.ts | 21 + .../typescript/typings/types/array.ts | 29 + .../typescript/typings/types/boolean.ts | 9 + .../typescript/typings/types/integer.ts | 9 + .../typescript/typings/types/null.ts | 9 + .../typescript/typings/types/number.ts | 9 + .../typescript/typings/types/object.ts | 38 + .../typescript/typings/types/string.ts | 9 + .../typescript/typings/typing.ts | 135 ++++ .../src/filters/typescript/index.ts | 517 ------------- .../src/filters/typescript/resolve.ts | 699 ------------------ .../src/filters/typescript/typings.ts | 318 -------- helper/crosslab-typescript-addon/src/index.ts | 9 +- .../basicValidation.ts.njk | 2 +- .../service-test/basicValidation.spec.ts.njk | 6 +- .../requestValidation.spec.ts.njk | 12 +- .../templates/service-test/types.spec.ts.njk | 2 +- .../templates/service/basicValidation.ts.njk | 2 +- .../service/requestValidation.ts.njk | 2 +- .../templates/service/routes.ts.njk | 10 +- .../templates/service/signatures.ts.njk | 4 +- 74 files changed, 1934 insertions(+), 1559 deletions(-) create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/addProperty.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/append.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/attribute.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/cap.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/clone.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/delete.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/endsWith.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/flatten.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/includes.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/index.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/sortByAttribute.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/split.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/startsWith.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/stringify.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/toStrings.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/unique.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatExpressPath.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatName.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatOperation.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/index.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/prettier.ts rename helper/crosslab-typescript-addon/src/{filters/typescript/validation.ts => filterCollections/typescript/filters/generate/generateBasicValidationFunctions.ts} (79%) create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateInvalidSchemas.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateSchemasWithoutUnrequired.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/index.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/getInvalidStatusCode.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/getPossibleScopeCombinations.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/index.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/index.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/index.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveOperations.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveSchemas.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/destructureSchema.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/index.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/inlineTypeDeclaration.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/standaloneTypings.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/typeDeclaration.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/typeDependencies.ts rename helper/crosslab-typescript-addon/src/{filters => filterCollections}/typescript/format.ts (100%) create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/index.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/removeReadWriteOnly.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveOperations.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/invalidSchemas.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/validSchemas.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/withoutUnrequired.ts rename helper/crosslab-typescript-addon/src/{filters => filterCollections}/typescript/schemas/userType.ts (100%) create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/types.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/allOf.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/anyOf.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/const.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/enum.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/oneOf.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/array.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/boolean.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/integer.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/null.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/number.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/object.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/string.ts create mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts delete mode 100644 helper/crosslab-typescript-addon/src/filters/typescript/index.ts delete mode 100644 helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts delete mode 100644 helper/crosslab-typescript-addon/src/filters/typescript/typings.ts diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/addProperty.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/addProperty.ts new file mode 100644 index 00000000..6483661e --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/addProperty.ts @@ -0,0 +1,10 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +function addProperty(object: { [k: string]: any }, propertyName: string, value: any) { + object[propertyName] = value +} + +export const addPropertyFilter: Filter = { + name: 'addProperty', + function: addProperty, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/append.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/append.ts new file mode 100644 index 00000000..10e60942 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/append.ts @@ -0,0 +1,10 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +function append(array: any[], value: any) { + array.push(value) +} + +export const appendFilter: Filter = { + name: 'append', + function: append, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/attribute.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/attribute.ts new file mode 100644 index 00000000..e963206f --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/attribute.ts @@ -0,0 +1,16 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter which attempts to return an array which only + * contains the requested attribute as its elements. + * @param array The array to be filtered. + * @param attributeName The name of the attribute. + */ +function attribute(array: any[], attributeName: string): any[] { + return array.map((item) => item[attributeName]) +} + +export const attributeFilter: Filter = { + name: 'attribute', + function: attribute, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/cap.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/cap.ts new file mode 100644 index 00000000..a5f9bafd --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/cap.ts @@ -0,0 +1,15 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter which capitalizes the first letter of a given string. + * @param string The string to be capitalized. + * @returns The capitalized string. + */ +function capitalize(string: string): string { + return string.charAt(0).toUpperCase() + string.slice(1) +} + +export const capitalizeFilter: Filter = { + name: 'cap', + function: capitalize, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/clone.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/clone.ts new file mode 100644 index 00000000..4bb6659c --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/clone.ts @@ -0,0 +1,14 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter that attempts to clone an object. + * @param object The object to be cloned. + */ +function clone(object: any) { + return JSON.parse(JSON.stringify(object)) +} + +export const cloneFilter: Filter = { + name: 'clone', + function: clone, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/delete.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/delete.ts new file mode 100644 index 00000000..fa3a3970 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/delete.ts @@ -0,0 +1,8 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const deleteFilter: Filter = { + name: 'delete', + function: (object: any, key: string) => { + delete object[key] + }, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/endsWith.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/endsWith.ts new file mode 100644 index 00000000..38d27b8b --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/endsWith.ts @@ -0,0 +1,17 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter that checks if a given string ends with the + * provided search string. + * @param string The string to be checked. + * @param searchString The search string. + * @returns True if the given string ends with the search string, else false. + */ +function endsWith(string: string, searchString: string) { + return string.endsWith(searchString as string) +} + +export const endsWithFilter: Filter = { + name: 'endsWith', + function: endsWith, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/flatten.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/flatten.ts new file mode 100644 index 00000000..18ecc90e --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/flatten.ts @@ -0,0 +1,20 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter which flattens an array. + * @param array The array to be flattened. + * @returns The flattened array. + */ +function flatten(array: any[]): any[] { + const newArray = [] + for (const item of array) { + if (Array.isArray(item)) newArray.push(...flatten(item)) + else newArray.push(item) + } + return newArray +} + +export const flattenFilter: Filter = { + name: 'flatten', + function: flatten, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/includes.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/includes.ts new file mode 100644 index 00000000..463a7229 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/includes.ts @@ -0,0 +1,10 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +function includes(string: string, searchString: string) { + return string.includes(searchString) +} + +export const includesFilter: Filter = { + name: 'includes', + function: includes, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/index.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/index.ts new file mode 100644 index 00000000..8043d737 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/index.ts @@ -0,0 +1,34 @@ +import { addPropertyFilter } from './addProperty' +import { appendFilter } from './append' +import { attributeFilter } from './attribute' +import { capitalizeFilter } from './cap' +import { cloneFilter } from './clone' +import { deleteFilter } from './delete' +import { endsWithFilter } from './endsWith' +import { flattenFilter } from './flatten' +import { includesFilter } from './includes' +import { sortByAttributeFilter } from './sortByAttribute' +import { splitFilter } from './split' +import { startsWithFilter } from './startsWith' +import { stringifyFilter } from './stringify' +import { toStringsFilter } from './toStrings' +import { uniqueFilter } from './unique' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const commonFilters: Filter[] = [ + addPropertyFilter, + appendFilter, + attributeFilter, + capitalizeFilter, + cloneFilter, + deleteFilter, + endsWithFilter, + flattenFilter, + includesFilter, + sortByAttributeFilter, + splitFilter, + startsWithFilter, + stringifyFilter, + toStringsFilter, + uniqueFilter, +] diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/sortByAttribute.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/sortByAttribute.ts new file mode 100644 index 00000000..db60e140 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/sortByAttribute.ts @@ -0,0 +1,33 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter which attempts to sort the given array into + * subarrays using the provided attribute name. + * @param array The array to be sorted. + * @param attributeName The name of the attribute to sort the array by. + * @returns A map containing the subarray for every value of the attribute. + */ +function sortByAttribute( + array: any[], + attributeName: string +): { + [k: string]: any[] +} { + const sorted: { + [k: string]: any[] + } = {} + + for (const item of array) { + if (!sorted[item[attributeName]]) sorted[item[attributeName]] = [] + sorted[item[attributeName]].push(item) + } + + delete sorted['undefined'] + + return sorted +} + +export const sortByAttributeFilter: Filter = { + name: 'sortByAttribute', + function: sortByAttribute, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/split.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/split.ts new file mode 100644 index 00000000..1284381d --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/split.ts @@ -0,0 +1,21 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter that splits a given string into an array of + * substrings divided by the provided split string. + * @param string The string to be split. + * @param splitString The split string. + * @example + * ``` + * "This is a test" | split(" ") = ["This", "is", "a", "test"] + * ``` + * @returns The array of substrings. + */ +function split(string: string, splitString: string) { + return string.split(splitString) +} + +export const splitFilter: Filter = { + name: 'split', + function: split, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/startsWith.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/startsWith.ts new file mode 100644 index 00000000..f14612f0 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/startsWith.ts @@ -0,0 +1,17 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter that checks if a given string starts with the + * provided search string. + * @param string The string to be checked. + * @param searchString The search string. + * @returns True if the given string ends with the search string, else false. + */ +function startsWith(string: string, searchString: string) { + return string.startsWith(searchString as string) +} + +export const startsWithFilter: Filter = { + name: 'startsWith', + function: startsWith, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/stringify.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/stringify.ts new file mode 100644 index 00000000..27f4f9a1 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/stringify.ts @@ -0,0 +1,16 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter which attempts to stringify a given object. + * @param object The object to be stringified. + * @param indentation The indentation to be used during JSON.stringify. + * @returns The stringified object. + */ +function stringify(object: any, indentation: number = 0): string { + return JSON.stringify(object, null, indentation) +} + +export const stringifyFilter: Filter = { + name: 'stringify', + function: stringify, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/toStrings.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/toStrings.ts new file mode 100644 index 00000000..cb1c49b1 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/toStrings.ts @@ -0,0 +1,16 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter which adds quotation marks to the elements of a + * given string array. + * @param array The string array for which to add quotation marks to its elements. + * @returns The string array with quotation marks around its elements. + */ +function toStrings(array: string[]): string[] { + return array.map((s) => `"${s}"`) +} + +export const toStringsFilter: Filter = { + name: 'toStrings', + function: toStrings, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/unique.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/unique.ts new file mode 100644 index 00000000..55d7831b --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/unique.ts @@ -0,0 +1,15 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter which filters duplicate values from an array. + * @param array The array to be filtered. + * @returns The array without duplicate values. + */ +function unique(array: any[]): any[] { + return array.filter((v, i, s) => s.indexOf(v) === i) +} + +export const uniqueFilter: Filter = { + name: 'unique', + function: unique, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatExpressPath.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatExpressPath.ts new file mode 100644 index 00000000..d2065131 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatExpressPath.ts @@ -0,0 +1,7 @@ +import { formatExpressPath } from '../../format' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const formatExpressPathFilter: Filter = { + name: 'formatExpressPath', + function: formatExpressPath, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatName.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatName.ts new file mode 100644 index 00000000..771c3569 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatName.ts @@ -0,0 +1,7 @@ +import { formatName } from '../../format' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const formatNameFilter: Filter = { + name: 'formatName', + function: formatName, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatOperation.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatOperation.ts new file mode 100644 index 00000000..08294ad1 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatOperation.ts @@ -0,0 +1,7 @@ +import { formatOperation } from '../../format' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const formatOperationFilter: Filter = { + name: 'formatOperation', + function: formatOperation, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/index.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/index.ts new file mode 100644 index 00000000..e342e826 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/index.ts @@ -0,0 +1,12 @@ +import { formatExpressPathFilter } from './formatExpressPath' +import { formatNameFilter } from './formatName' +import { formatOperationFilter } from './formatOperation' +import { prettierFilter } from './prettier' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const formatFilters: Filter[] = [ + formatExpressPathFilter, + formatNameFilter, + formatOperationFilter, + prettierFilter, +] diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/prettier.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/prettier.ts new file mode 100644 index 00000000..863b4c7e --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/prettier.ts @@ -0,0 +1,16 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' +import { format } from 'prettier' + +/** + * This function defines a filter that applies prettier to a string. + * @param string The string to apply prettier on. + * @returns The formatted string + */ +function prettier(string: string) { + return format(string, { parser: 'typescript', tabWidth: 4, singleQuote: true }) +} + +export const prettierFilter: Filter = { + name: 'prettier', + function: prettier, +} diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateBasicValidationFunctions.ts similarity index 79% rename from helper/crosslab-typescript-addon/src/filters/typescript/validation.ts rename to helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateBasicValidationFunctions.ts index bee20d6d..6c21a783 100644 --- a/helper/crosslab-typescript-addon/src/filters/typescript/validation.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateBasicValidationFunctions.ts @@ -1,7 +1,7 @@ -import { ExtendedSchema } from './resolve' +import { ExtendedSchema } from '../../types' +import { Filter } from '@cross-lab-project/openapi-codegen' import Ajv from 'ajv' import addFormats from 'ajv-formats' -// import { format } from 'prettier' import standaloneCode from 'ajv/dist/standalone' /** @@ -10,7 +10,7 @@ import standaloneCode from 'ajv/dist/standalone' * @param schemas The schemas for which to generate the validation functions. * @returns The validation functions as a string of code. */ -export function validation_filter(schemas: ExtendedSchema[]) { +function generateBasicValidationFunctions(schemas: ExtendedSchema[]) { const ajv: Ajv = new Ajv({ code: { source: true, esm: true }, verbose: true, @@ -39,3 +39,8 @@ export function validation_filter(schemas: ExtendedSchema[]) { } return standaloneCode(ajv, mapping) } + +export const generateBasicValidationFunctionsFilter: Filter = { + name: 'generateBasicValidationFunctions', + function: generateBasicValidationFunctions, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateInvalidSchemas.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateInvalidSchemas.ts new file mode 100644 index 00000000..cc05d9b1 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateInvalidSchemas.ts @@ -0,0 +1,7 @@ +import { generateInvalidSchemas } from '../../schema-generation/invalidSchemas' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const generateInvalidSchemasFilter: Filter = { + name: 'generateInvalidSchemas', + function: generateInvalidSchemas, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateSchemasWithoutUnrequired.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateSchemasWithoutUnrequired.ts new file mode 100644 index 00000000..c2a125a7 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/generateSchemasWithoutUnrequired.ts @@ -0,0 +1,7 @@ +import { generateSchemasWithoutUnrequired } from '../../schema-generation/withoutUnrequired' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const generateSchemasWithoutUnrequiredFilter: Filter = { + name: 'generateSchemasWithoutUnrequired', + function: generateSchemasWithoutUnrequired, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/index.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/index.ts new file mode 100644 index 00000000..0e14923c --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/generate/index.ts @@ -0,0 +1,10 @@ +import { generateBasicValidationFunctionsFilter } from './generateBasicValidationFunctions' +import { generateInvalidSchemasFilter } from './generateInvalidSchemas' +import { generateSchemasWithoutUnrequiredFilter } from './generateSchemasWithoutUnrequired' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const generateFilters: Filter[] = [ + generateBasicValidationFunctionsFilter, + generateInvalidSchemasFilter, + generateSchemasWithoutUnrequiredFilter, +] diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/getInvalidStatusCode.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/getInvalidStatusCode.ts new file mode 100644 index 00000000..c0d6eb82 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/getInvalidStatusCode.ts @@ -0,0 +1,40 @@ +import { SimplifiedOperation } from '../../types' +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function gets an invalid status code for an operation. + * @param operation The operation for which to get the invalid status code. + * @returns An invalid status code for the provided operation. + */ +function getInvalidStatusCode(operation: SimplifiedOperation) { + const invalidStatusCodes: number[] = [] + + for (let i = 100; i < 600; i++) { + invalidStatusCodes.push(i) + } + + for (const response of operation.responses ?? []) { + if (response.status.endsWith('XX')) { + const start = parseInt(response.status.replace(/X/g, '0')) + for (let i = start; i < start + 100; i++) { + const foundIndex = invalidStatusCodes.findIndex( + (statusCode) => statusCode === i + ) + if (foundIndex > -1) invalidStatusCodes.splice(foundIndex, 1) + } + } else { + const parsedStatusCode = parseInt(response.status) + const foundIndex = invalidStatusCodes.findIndex( + (statusCode) => statusCode === parsedStatusCode + ) + if (foundIndex > -1) invalidStatusCodes.splice(foundIndex, 1) + } + } + + return invalidStatusCodes.length > 0 ? invalidStatusCodes[0] : undefined +} + +export const getInvalidStatusCodeFilter: Filter = { + name: 'getInvalidStatusCode', + function: getInvalidStatusCode, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/getPossibleScopeCombinations.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/getPossibleScopeCombinations.ts new file mode 100644 index 00000000..869ca058 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/getPossibleScopeCombinations.ts @@ -0,0 +1,31 @@ +import { Filter } from '@cross-lab-project/openapi-codegen' +import { OpenAPIV3_1 } from 'openapi-types' + +function getPossibleScopeCombinations( + security?: OpenAPIV3_1.SecurityRequirementObject[] +) { + const possibleCombinations: [string, string][][] = [] + for (const securityRequirement of security ?? []) { + let combinations: [string, string][][] = [] + for (const key in securityRequirement) { + const scopes = securityRequirement[key] + if (combinations.length === 0) { + for (const scope of scopes) { + combinations.push([[key, scope]]) + } + } else { + for (const scope of scopes) { + combinations = combinations.map((comb) => [...comb, [key, scope]]) + } + } + } + possibleCombinations.push(...combinations) + } + + return possibleCombinations +} + +export const getPossibleScopeCombinationsFilter: Filter = { + name: 'getPossibleScopeCombinations', + function: getPossibleScopeCombinations, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/index.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/index.ts new file mode 100644 index 00000000..6f759ac8 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/helper/index.ts @@ -0,0 +1,8 @@ +import { getInvalidStatusCodeFilter } from './getInvalidStatusCode' +import { getPossibleScopeCombinationsFilter } from './getPossibleScopeCombinations' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const helperFilters: Filter[] = [ + getInvalidStatusCodeFilter, + getPossibleScopeCombinationsFilter, +] diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/index.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/index.ts new file mode 100644 index 00000000..91211184 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/index.ts @@ -0,0 +1,16 @@ +import { commonFilters } from './common' +import { formatFilters } from './format' +import { generateFilters } from './generate' +import { helperFilters } from './helper' +import { resolveFilters } from './resolve' +import { typingFilters } from './typing' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const filters: Filter[] = [ + ...commonFilters, + ...formatFilters, + ...generateFilters, + ...helperFilters, + ...resolveFilters, + ...typingFilters, +] diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/index.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/index.ts new file mode 100644 index 00000000..39ffb9f1 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/index.ts @@ -0,0 +1,5 @@ +import { resolveOperationsFilter } from './resolveOperations' +import { resolveSchemasFilter } from './resolveSchemas' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const resolveFilters: Filter[] = [resolveOperationsFilter, resolveSchemasFilter] diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveOperations.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveOperations.ts new file mode 100644 index 00000000..b7d676b7 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveOperations.ts @@ -0,0 +1,8 @@ +import { resolveOperations } from '../../resolve/resolveOperations' +import { Filter } from '@cross-lab-project/openapi-codegen' +import { OpenAPIV3_1 } from 'openapi-types' + +export const resolveOperationsFilter: Filter = { + name: 'resolveOperations', + function: (api: OpenAPIV3_1.Document) => resolveOperations(api), +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveSchemas.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveSchemas.ts new file mode 100644 index 00000000..4fa4ac29 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveSchemas.ts @@ -0,0 +1,9 @@ +import { resolveSchemas } from '../../resolve/resolveSchemas' +import { Filter } from '@cross-lab-project/openapi-codegen' +import { OpenAPIV3_1 } from 'openapi-types' + +export const resolveSchemasFilter: Filter = { + name: 'resolveSchemas', + function: (api: OpenAPIV3_1.Document, isService: boolean = true) => + resolveSchemas(api, isService), +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/destructureSchema.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/destructureSchema.ts new file mode 100644 index 00000000..8516999e --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/destructureSchema.ts @@ -0,0 +1,15 @@ +import { ExtendedSchema } from '../../types' +import { destructureSchema } from '../../typings/destructure' +import { Filter } from '@cross-lab-project/openapi-codegen' +import { OpenAPIV3_1 } from 'openapi-types' + +export const destructureSchemaFilter: Filter = { + name: 'destructureSchema', + function: ( + schema: OpenAPIV3_1.SchemaObject, + options?: { + prefixTypes?: string + context?: ExtendedSchema[] + } + ) => destructureSchema(schema, options), +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/index.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/index.ts new file mode 100644 index 00000000..254643a0 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/index.ts @@ -0,0 +1,14 @@ +import { destructureSchemaFilter } from './destructureSchema' +import { inlineTypeDeclarationFilter } from './inlineTypeDeclaration' +import { standaloneTypingsFilter } from './standaloneTypings' +import { typeDeclarationFilter } from './typeDeclaration' +import { typeDependenciesFilter } from './typeDependencies' +import { Filter } from '@cross-lab-project/openapi-codegen' + +export const typingFilters: Filter[] = [ + destructureSchemaFilter, + inlineTypeDeclarationFilter, + standaloneTypingsFilter, + typeDeclarationFilter, + typeDependenciesFilter, +] diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/inlineTypeDeclaration.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/inlineTypeDeclaration.ts new file mode 100644 index 00000000..c1a7a24e --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/inlineTypeDeclaration.ts @@ -0,0 +1,18 @@ +import { generateTyping } from '../../typings/typing' +import { Filter } from '@cross-lab-project/openapi-codegen' +import { OpenAPIV3_1 } from 'openapi-types' + +/** + * This function defines a filter which attempts to generate the inline type + * declaration for a given schema. + * @param schema The schema for which to generate the inline type declaration. + * @returns The generated inline type declaration. + */ +function inlineTypeDeclaration(schema: OpenAPIV3_1.SchemaObject) { + return generateTyping(schema, { inline: true }).typeDeclaration +} + +export const inlineTypeDeclarationFilter: Filter = { + name: 'inlineTypeDeclaration', + function: inlineTypeDeclaration, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/standaloneTypings.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/standaloneTypings.ts new file mode 100644 index 00000000..04ef9f47 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/standaloneTypings.ts @@ -0,0 +1,70 @@ +import { formatName } from '../../format' +import { ExtendedSchema } from '../../types' +import { generateTyping } from '../../typings/typing' +import { Filter } from '@cross-lab-project/openapi-codegen' + +/** + * This function defines a filter which generates the typings for all provided + * schemas which have the property 'x-standalone' set to true. + * @param extendedSchemas The schemas for which to generate the typings. + * @returns The typings of the schemas. + */ +function standaloneTypings(extendedSchemas: ExtendedSchema[]) { + const standaloneSchemas = extendedSchemas.filter( + (extendedSchema) => + extendedSchema['x-standalone'] && extendedSchema['x-schema-type'] === 'all' + ) + + const mappedStandaloneSchemas = standaloneSchemas.map((extendedSchema) => { + const requestSchema = extendedSchemas.find( + (es) => es['x-location'] === extendedSchema['x-location'] + '_request' + ) + const responseSchema = extendedSchemas.find( + (es) => es['x-location'] === extendedSchema['x-location'] + '_response' + ) + if (!requestSchema || !responseSchema) + throw new Error('Could not find request-/response-schema') + return { + all: extendedSchema, + request: requestSchema, + response: responseSchema, + } + }) + + return mappedStandaloneSchemas + .map((schemas) => { + const name = schemas.all.title + ? formatName(schemas.all.title) + : 'MISSING_NAME' + const tdAll = generateTyping(schemas.all, { + inline: false, + resolveDirectly: false, + context: standaloneSchemas, + }) + const tdRequest = generateTyping(schemas.request, { + inline: false, + resolveDirectly: false, + context: standaloneSchemas, + }) + const tdResponse = generateTyping(schemas.response, { + inline: false, + resolveDirectly: false, + context: standaloneSchemas, + }) + return ` + ${tdAll.comment}export type ${name} = T extends "all" + ? ${tdAll.typeDeclaration} + : T extends "request" + ? ${tdRequest.typeDeclaration} + : T extends "response" + ? ${tdResponse.typeDeclaration} + : never + ` + }) + .join('\n\n') +} + +export const standaloneTypingsFilter: Filter = { + name: 'standaloneTypings', + function: standaloneTypings, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/typeDeclaration.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/typeDeclaration.ts new file mode 100644 index 00000000..60b1833c --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/typeDeclaration.ts @@ -0,0 +1,24 @@ +import { ExtendedSchema } from '../../types' +import { TypingOptions, generateTyping } from '../../typings/typing' +import { Filter } from '@cross-lab-project/openapi-codegen' +import { OpenAPIV3_1 } from 'openapi-types' + +/** + * This function defines a filter which attempts to generate the type declaration + * for a given schema. + * @param schema The schema for which to generate the type declaration. + * @returns The generated type declaration. + */ +function typeDeclaration( + schema: OpenAPIV3_1.SchemaObject, + extendedSchemas: ExtendedSchema[] = [], + options?: TypingOptions +) { + return generateTyping(schema, { ...options, context: extendedSchemas }) + .typeDeclaration +} + +export const typeDeclarationFilter: Filter = { + name: 'typeDeclaration', + function: typeDeclaration, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/typeDependencies.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/typeDependencies.ts new file mode 100644 index 00000000..9c2cc00e --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/typeDependencies.ts @@ -0,0 +1,22 @@ +import { ExtendedSchema } from '../../types' +import { generateTyping } from '../../typings/typing' +import { Filter } from '@cross-lab-project/openapi-codegen' +import { OpenAPIV3_1 } from 'openapi-types' + +/** + * This function defines a filter which attempts to find the type dependencies for + * a given schema. + * @param schema The schema for which to find the type dependencies. + * @returns The found type dependencies. + */ +function typeDependencies( + schema: OpenAPIV3_1.SchemaObject, + extendedSchemas: ExtendedSchema[] = [] +) { + return generateTyping(schema, { context: extendedSchemas }).typeDependencies +} + +export const typeDependenciesFilter: Filter = { + name: 'typeDependencies', + function: typeDependencies, +} diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/format.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/format.ts similarity index 100% rename from helper/crosslab-typescript-addon/src/filters/typescript/format.ts rename to helper/crosslab-typescript-addon/src/filterCollections/typescript/format.ts diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/index.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/index.ts new file mode 100644 index 00000000..525b2cb3 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/index.ts @@ -0,0 +1,10 @@ +import { filters } from './filters' +import { FilterCollection } from '@cross-lab-project/openapi-codegen' + +/** + * The filter collection for typescript. + */ +export const TypeScriptFilterCollection: FilterCollection = { + name: 'typescript', + filters: filters, +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/removeReadWriteOnly.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/removeReadWriteOnly.ts new file mode 100644 index 00000000..cf37c0b7 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/removeReadWriteOnly.ts @@ -0,0 +1,114 @@ +import { ExtendedSchema } from '../types' +import { OpenAPIV3_1 } from 'openapi-types' + +export function removeReadOnly(schema: ExtendedSchema): ExtendedSchema { + return { + ...removeReadOrWriteOnly(schema, 'readOnly'), + 'x-location': schema['x-location'], + 'x-name': schema['x-name'], + 'x-schema-type': schema['x-schema-type'], + 'x-service-name': schema['x-service-name'], + 'x-standalone': schema['x-standalone'], + } +} + +export function removeWriteOnly(schema: ExtendedSchema): ExtendedSchema { + return { + ...removeReadOrWriteOnly(schema, 'writeOnly'), + 'x-location': schema['x-location'], + 'x-name': schema['x-name'], + 'x-schema-type': schema['x-schema-type'], + 'x-service-name': schema['x-service-name'], + 'x-standalone': schema['x-standalone'], + } +} + +function removeReadOrWriteOnly( + schema: OpenAPIV3_1.SchemaObject, + readOrWriteOnly: 'readOnly' | 'writeOnly' +): OpenAPIV3_1.SchemaObject { + const newSchema = JSON.parse(JSON.stringify(schema)) as ExtendedSchema + + switch (newSchema.type) { + case 'array': + return handleArray(newSchema, readOrWriteOnly) + case 'boolean': + return newSchema + case 'integer': + return newSchema + case 'null': + return newSchema + case 'number': + return newSchema + case 'object': + return handleObject(newSchema, readOrWriteOnly) + case 'string': + return newSchema + default: + return handleUndefined(newSchema, readOrWriteOnly) + } +} + +function handleArray( + schema: OpenAPIV3_1.SchemaObject, + readOrWriteOnly: 'readOnly' | 'writeOnly' +): OpenAPIV3_1.SchemaObject { + if (schema.type !== 'array') throw new Error("Schema is not of type 'array'") + + schema.items = removeReadOrWriteOnly(schema.items, readOrWriteOnly) + + return schema +} + +function handleObject( + schema: OpenAPIV3_1.SchemaObject, + readOrWriteOnly: 'readOnly' | 'writeOnly' +): OpenAPIV3_1.SchemaObject { + if (schema.type !== 'object') throw new Error("Schema is not of type 'object'") + + for (const propertyName in schema.properties) { + if ( + (schema.properties[propertyName] as OpenAPIV3_1.SchemaObject)[readOrWriteOnly] + ) { + delete schema.properties[propertyName] + if (schema.required?.includes(propertyName)) { + schema.required = schema.required.filter((name) => name !== propertyName) + } + } + } + + schema.allOf = schema.allOf?.map((allOfSchema) => + removeReadOrWriteOnly(allOfSchema, readOrWriteOnly) + ) + + schema.anyOf = schema.anyOf?.map((anyOfSchema) => + removeReadOrWriteOnly(anyOfSchema, readOrWriteOnly) + ) + + schema.oneOf = schema.oneOf?.map((oneOfSchema) => + removeReadOrWriteOnly(oneOfSchema, readOrWriteOnly) + ) + + return schema +} + +function handleUndefined( + schema: OpenAPIV3_1.SchemaObject, + readOrWriteOnly: 'readOnly' | 'writeOnly' +): OpenAPIV3_1.SchemaObject { + if (schema.type) throw new Error('Schema type is not undefined') + + schema.allOf = schema.allOf?.map((allOfSchema) => + removeReadOrWriteOnly(allOfSchema, readOrWriteOnly) + ) + + schema.anyOf = schema.anyOf?.map((anyOfSchema) => + removeReadOrWriteOnly(anyOfSchema, readOrWriteOnly) + ) + + schema.oneOf = schema.oneOf?.map((oneOfSchema) => + removeReadOrWriteOnly(oneOfSchema, readOrWriteOnly) + ) + + return schema +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveOperations.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveOperations.ts new file mode 100644 index 00000000..ae7b880f --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveOperations.ts @@ -0,0 +1,151 @@ +import { formatName, formatOperation } from '../format' +import { SimplifiedOperation, SimplifiedParameter, SimplifiedResponse } from '../types' +import { OpenAPIV3_1 } from 'openapi-types' + +/** + * This function tries to resolve the Operations of a given OpenAPI document. + * @param api The OpenAPI document for which to resolve the Operations. + * @returns The resolved Operations. + */ +export function resolveOperations(api: OpenAPIV3_1.Document): SimplifiedOperation[] { + const simplifiedOperations: SimplifiedOperation[] = [] + + if (api.paths) simplifiedOperations.push(...parsePaths(api.paths)) + + return simplifiedOperations +} + +function parsePaths(paths: OpenAPIV3_1.PathsObject): SimplifiedOperation[] { + const simplifiedOperations: SimplifiedOperation[] = [] + + for (const path of Object.keys(paths)) { + const pathItem = paths[path] as OpenAPIV3_1.PathItemObject + simplifiedOperations.push(...parsePathItem(path, pathItem)) + } + + return simplifiedOperations +} + +function parsePathItem( + path: string, + pathItem: OpenAPIV3_1.PathItemObject +): SimplifiedOperation[] { + const simplifiedOperations: SimplifiedOperation[] = [] + + for (const method in pathItem) { + const operation = pathItem[ + method as OpenAPIV3_1.HttpMethods + ] as OpenAPIV3_1.OperationObject + + simplifiedOperations.push(parseMethod(path, method, operation)) + } + + return simplifiedOperations +} + +function parseMethod( + path: string, + method: string, + operation: OpenAPIV3_1.OperationObject +): SimplifiedOperation { + // Create SimplifiedOperation with known properties + const simplifiedOperation: SimplifiedOperation = { + name: formatOperation(path, method), + path: path, + method: method, + serviceName: (operation as any)['x-service-name'], + operationId: operation.operationId ?? '', + security: operation.security, + summary: operation.summary ?? '', + external: (operation as any)['x-internal'] ? false : true, + destructureInput: (operation as any)['x-destructure-input'] ?? false, + buildUrl: (operation as any)['x-build-url'] ?? false, + optionalUrl: (operation as any)['x-optional-url'] ?? false, + isProxyRequest: (operation as any)['x-proxy-request'] ?? false, + } + + // Search for parameters to add + const parameters = operation.parameters as OpenAPIV3_1.ParameterObject[] | undefined + if (parameters) parseParameters(parameters, simplifiedOperation) + + // Search for requestBody to add + const requestBody = operation.requestBody as OpenAPIV3_1.RequestBodyObject | undefined + if (requestBody) parseRequestBody(requestBody, simplifiedOperation) + + // Search for responses to add + const responses = operation.responses as OpenAPIV3_1.ResponsesObject | undefined + if (responses) parseResponses(responses, simplifiedOperation) + + return simplifiedOperation +} + +function parseParameters( + parameters: OpenAPIV3_1.ParameterObject[], + simplifiedOperation: SimplifiedOperation +) { + for (const parameter of parameters) { + simplifiedOperation.parameters ??= [] + const simplifiedParameter: SimplifiedParameter = { + name: parameter.name, + required: parameter.required ?? false, + in: parameter.in, + description: parameter.description, + schema: parameter.schema as OpenAPIV3_1.SchemaObject | undefined, + } + simplifiedOperation.parameters.push(simplifiedParameter) + } +} + +function parseRequestBody( + requestBody: OpenAPIV3_1.RequestBodyObject, + simplifiedOperation: SimplifiedOperation +) { + simplifiedOperation.requestBody = { + description: requestBody.description, + required: requestBody.required ?? false, + } + + if (requestBody.content && requestBody.content['application/json'].schema) { + simplifiedOperation.requestBody.schema = + requestBody.content['application/json'].schema + } +} + +function parseResponses( + responses: OpenAPIV3_1.ResponsesObject, + simplifiedOperation: SimplifiedOperation +) { + for (const status in responses) { + const response = responses[status] as OpenAPIV3_1.ResponseObject + simplifiedOperation.responses ??= [] + const simplifiedResponse: SimplifiedResponse = { + status: status, + description: response.description, + } + + // Add schema of response if present + if (response.content && response.content['application/json'].schema) { + simplifiedResponse.schema = response.content['application/json'].schema + } + + // Add headers of response if present + if (response.headers) parseHeaders(response.headers, simplifiedResponse) + + simplifiedOperation.responses.push(simplifiedResponse) + } +} + +function parseHeaders( + headers: { [header: string]: OpenAPIV3_1.HeaderObject }, + simplifiedResponse: SimplifiedResponse +) { + simplifiedResponse.headers = [] + for (const headerName in headers) { + const header = headers[headerName] as OpenAPIV3_1.HeaderObject + simplifiedResponse.headers.push({ + name: formatName(headerName), + required: header.required ?? false, + schema: header.schema as OpenAPIV3_1.SchemaObject | undefined, + }) + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts new file mode 100644 index 00000000..f6457f01 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts @@ -0,0 +1,258 @@ +import { formatName, formatOperation } from '../format' +import { userTypeSchema } from '../schemas/userType' +import { ExtendedSchema } from '../types' +import { removeReadOnly, removeWriteOnly } from './removeReadWriteOnly' +import { OpenAPIV3_1 } from 'openapi-types' + +/** + * This function tries to resolve the Schemas of a given OpenAPI document. + * @param api The OpenAPI document for which to resolve the Schemas. + * @param isService + * If true the UserType schema is added and method path will be used for + * naming. Otherwise the operationId will be used for naming. + * @returns + * The resolved Schemas with additional properties 'x-name', 'x-standalone' + * and 'x-location' + */ +export function resolveSchemas( + inputApi: OpenAPIV3_1.Document, + isService: boolean = true +): ExtendedSchema[] { + const extendedSchemas: ExtendedSchema[] = [] + const api = JSON.parse(JSON.stringify(inputApi)) as OpenAPIV3_1.Document + + // Add UserType schema + if (isService) + extendedSchemas.push({ + ...userTypeSchema, + 'x-standalone': true, + 'x-name': 'UserType', + 'x-location': `#/components/schemas/user_type`, + 'x-service-name': 'Utility', + 'x-schema-type': 'all', + }) + + // Search in components + if (api.components) extendedSchemas.push(...parseComponents(api.components)) + + // Search in paths + if (api.paths) extendedSchemas.push(...parsePaths(api.paths, isService)) + + const _extendedSchemas = JSON.parse( + JSON.stringify(extendedSchemas) + ) as ExtendedSchema[] + + for (const extendedSchema of _extendedSchemas) { + const requestSchema = removeReadOnly(extendedSchema) + const responseSchema = removeWriteOnly(extendedSchema) + + requestSchema['x-schema-type'] = 'request' + responseSchema['x-schema-type'] = 'response' + + requestSchema['x-name'] += 'Request' + responseSchema['x-name'] += 'Response' + + requestSchema['x-location'] += '_request' + responseSchema['x-location'] += '_response' + + extendedSchemas.push(...[requestSchema, responseSchema]) + } + + return extendedSchemas +} + +function parseComponents(components: OpenAPIV3_1.ComponentsObject): ExtendedSchema[] { + const extendedSchemas: ExtendedSchema[] = [] + + // Search for schemas in components + if (components.schemas) + extendedSchemas.push(...parseComponentsSchemas(components.schemas)) + // Search for parameters in components + if (components.parameters) + extendedSchemas.push(...parseComponentsParameters(components.parameters)) + + return extendedSchemas +} + +function parseComponentsSchemas( + schemas: OpenAPIV3_1.ComponentsObject['schemas'] +): ExtendedSchema[] { + const extendedSchemas: ExtendedSchema[] = [] + + for (const schemaName in schemas) { + const name = formatName(schemas[schemaName].title ?? 'MISSING') + extendedSchemas.push({ + ...schemas[schemaName], + 'x-standalone': true, + 'x-name': name, + 'x-location': `#/components/schemas/${schemaName}`, + 'x-service-name': (schemas[schemaName] as any)['x-service-name'], + 'x-schema-type': 'all', + }) + } + + return extendedSchemas +} + +function parseComponentsParameters( + parameters: OpenAPIV3_1.ComponentsObject['parameters'] +): ExtendedSchema[] { + const extendedSchemas: ExtendedSchema[] = [] + + for (const parameterName in parameters) { + const parameter = parameters[parameterName] as OpenAPIV3_1.ParameterObject + const schema = parameter.schema as OpenAPIV3_1.SchemaObject + extendedSchemas.push({ + ...schema, + 'x-standalone': false, + 'x-name': formatName(parameter.name), + 'x-location': `#/components/parameters/${parameterName}/schema`, + 'x-service-name': (schema as any)['x-service-name'], + 'x-schema-type': 'all', + }) + } + + return extendedSchemas +} + +function parsePaths(paths: OpenAPIV3_1.PathsObject, isService: boolean) { + const extendedSchemas: ExtendedSchema[] = [] + + for (const path in paths) { + const pathItem = paths[path] as OpenAPIV3_1.PathItemObject + extendedSchemas.push(...parsePathItem(pathItem, path, isService)) + } + + return extendedSchemas +} + +function parsePathItem( + pathItem: OpenAPIV3_1.PathItemObject, + path: string, + isService: boolean +): ExtendedSchema[] { + const extendedSchemas: ExtendedSchema[] = [] + + for (const method of Object.keys(pathItem)) { + const operation = pathItem[ + method as OpenAPIV3_1.HttpMethods + ] as OpenAPIV3_1.OperationObject + + const requestBody = operation.requestBody as + | OpenAPIV3_1.RequestBodyObject + | undefined + + // Add requestBody schema if present + if (requestBody) { + const extendedSchema = parseRequestBody( + requestBody, + operation, + path, + method, + isService + ) + if (extendedSchema) extendedSchemas.push(extendedSchema) + } + + // Search for response schemas + if (operation.responses) + extendedSchemas.push( + ...parseResponses(operation.responses, operation, path, method, isService) + ) + } + return extendedSchemas +} + +function parseRequestBody( + requestBody: OpenAPIV3_1.RequestBodyObject, + operation: OpenAPIV3_1.OperationObject, + path: string, + method: string, + isService: boolean +): ExtendedSchema | undefined { + const schema = requestBody.content['application/json'].schema + return schema + ? { + ...schema, + 'x-standalone': false, + 'x-name': isService + ? formatOperation(path, method) + 'RequestBody' + : formatName(operation.operationId ?? '', false) + 'Body', + 'x-location': `#/paths/${path}/${method}/requestBody/content/application/json/schema`, + 'x-service-name': (operation as any)['x-service-name'], + 'x-schema-type': 'all', + } + : undefined +} + +function parseResponses( + responses: OpenAPIV3_1.ResponsesObject, + operation: OpenAPIV3_1.OperationObject, + path: string, + method: string, + isService: boolean +): ExtendedSchema[] { + const extendedSchemas: ExtendedSchema[] = [] + + for (const status in responses) { + const response = responses[status] as OpenAPIV3_1.ResponseObject + const content = response.content + if (content && content['application/json'].schema) { + extendedSchemas.push({ + ...content['application/json'].schema, + 'x-standalone': false, + 'x-name': isService + ? formatOperation(path, method) + 'Response' + status + : formatName(operation.operationId ?? '', false) + + 'Response' + + status, + 'x-location': `#/paths/${path}/${method}/responses/${status}/content/application/json/schema`, + 'x-service-name': (operation as any)['x-service-name'], + 'x-schema-type': 'all', + }) + } + if (response.headers) + extendedSchemas.push( + ...parseHeaders( + response.headers, + operation, + path, + method, + status, + isService + ) + ) + } + + return extendedSchemas +} + +function parseHeaders( + headers: OpenAPIV3_1.ResponseObject['headers'], + operation: OpenAPIV3_1.OperationObject, + path: string, + method: string, + status: string, + isService: boolean +): ExtendedSchema[] { + const extendedSchemas: ExtendedSchema[] = [] + + for (const headerName in headers) { + const header = headers[headerName] as OpenAPIV3_1.HeaderObject + if (header.schema) { + extendedSchemas.push({ + ...header.schema, + 'x-standalone': false, + 'x-name': isService + ? formatOperation(path, method) + 'Header' + formatName(headerName) + : formatName(operation.operationId ?? '', false) + + formatName(headerName), + 'x-location': `#/paths/${path}/${method}/responses/${status}/headers/${headerName}/schema`, + 'x-service-name': (operation as any)['x-service-name'], + 'x-schema-type': 'all', + }) + } + } + + return extendedSchemas +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/invalidSchemas.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/invalidSchemas.ts new file mode 100644 index 00000000..59843f04 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/invalidSchemas.ts @@ -0,0 +1,203 @@ +import { OpenAPIV3_1 } from 'openapi-types' + +/** + * This function attempts to generate invalid versions of a given schema by recursively removing + * required attributes or replacing them with invalid types / formats. + * @param schema The schema to use as a template. + * @param prefix A prefix to generate the path to the removed property. + * @returns A list of invalid versions of the template schema with the path of the removed property. + */ +export function generateInvalidSchemas( + schema: OpenAPIV3_1.SchemaObject, + prefix: string = 'schema' +): { + schema: OpenAPIV3_1.SchemaObject + path: string + operation: 'remove' | 'change-type' | 'remove-format' | 'remove-enum' | 'negate-type' +}[] { + const invalidSchemas: ReturnType = [] + + const anySchemas: OpenAPIV3_1.SchemaObject[] = [ + { + type: 'array', + items: {}, + }, + { + type: 'boolean', + }, + { + type: 'integer', + }, + { + type: 'null', + }, + { + type: 'number', + }, + { + type: 'object', + }, + { + type: 'string', + }, + ] + + if (schema.allOf) { + for (const [index, subSchema] of schema.allOf.entries()) { + const invalidSubSchemas = generateInvalidSchemas( + subSchema, + `${prefix}.allOf[${index}]` + ) + invalidSchemas.push(...invalidSubSchemas) + } + } + + if (schema.anyOf) { + for (const [index, subSchema] of schema.anyOf.entries()) { + const invalidSubSchemas = generateInvalidSchemas( + subSchema, + `${prefix}.anyOf[${index}]` + ) + invalidSchemas.push(...invalidSubSchemas) + } + } + + if (schema.oneOf) { + for (const [index, subSchema] of schema.oneOf.entries()) { + const invalidSubSchemas = generateInvalidSchemas( + subSchema, + `${prefix}.oneOf[${index}]` + ) + invalidSchemas.push(...invalidSubSchemas) + } + } + + // remove format + if (schema.format) { + const invalidSchema = { + ...schema, + } + delete invalidSchema.format + + invalidSchemas.push({ + schema: invalidSchema, + path: `${prefix}`, + operation: 'remove-format', + }) + } + + // remove enum + if (schema.enum) { + const invalidSchema = { + ...schema, + } + delete invalidSchema.enum + + invalidSchemas.push({ + schema: invalidSchema, + path: `${prefix}`, + operation: 'remove-enum', + }) + } + + // change type + if (schema.type) { + invalidSchemas.push({ + schema: { + anyOf: [...anySchemas.filter((s) => s.type !== schema.type)], + }, + path: `${prefix}`, + operation: 'change-type', + }) + } + + invalidSchemas.push({ + schema: { + not: schema, + }, + path: `${prefix}`, + operation: 'negate-type', + }) + + switch (schema.type) { + case 'object': + if (schema.properties) { + // remove required properties + if (schema.required) { + for (const requiredProperty of schema.required) { + const removedSchema = { + ...schema, + properties: { + ...schema.properties, + }, + } + removedSchema.required = removedSchema.required?.filter( + (r) => r !== requiredProperty + ) + delete removedSchema.properties![requiredProperty] + + invalidSchemas.push({ + schema: removedSchema, + path: `${prefix}.${requiredProperty}`, + operation: 'remove', + }) + } + } + + // recurse into properties + for (const propertyName in schema.properties) { + const property = schema.properties[ + propertyName + ] as OpenAPIV3_1.SchemaObject + + const invalidPropertySchemas = generateInvalidSchemas( + property, + `${prefix}.${propertyName}` + ) + + for (const invalidPropertySchema of invalidPropertySchemas) { + const invalidSchema = { + ...schema, + properties: { + ...schema.properties, + }, + } + invalidSchema.properties[propertyName] = + invalidPropertySchema.schema + + if (!invalidSchema.required?.find((r) => r === propertyName)) { + if (!invalidSchema.required) + invalidSchema.required = [propertyName] + else invalidSchema.required.push(propertyName) + } + + invalidSchemas.push({ + ...invalidPropertySchema, + schema: invalidSchema, + }) + } + } + } + break + case 'array': + const invalidItemsSchemas = generateInvalidSchemas( + schema.items, + `${prefix}.items` + ) + for (const invalidItemsSchema of invalidItemsSchemas) { + const currentSchema = schema + invalidSchemas.push({ + ...invalidItemsSchema, + schema: { + ...currentSchema, + items: invalidItemsSchema.schema, + }, + }) + } + break + default: + break + } + + return invalidSchemas +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/validSchemas.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/validSchemas.ts new file mode 100644 index 00000000..e69de29b diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/withoutUnrequired.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/withoutUnrequired.ts new file mode 100644 index 00000000..2cdd7bb7 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/withoutUnrequired.ts @@ -0,0 +1,62 @@ +import { OpenAPIV3_1 } from 'openapi-types' + +/** + * Generates versions of a given schema without one of the unrequired properties. + * @param schema The schema for which to generate the versions. + * @param prefix A prefix to generate the path to the removed property. + * @returns A list of schemas with each one missing an unrequired property. + */ +export function generateSchemasWithoutUnrequired( + schema: OpenAPIV3_1.SchemaObject, + prefix: string = 'schema' +): { + schema: OpenAPIV3_1.SchemaObject + path: string +}[] { + const schemasWithoutUnrequired: ReturnType = + [] + + if (schema.properties) { + for (const propertyName in schema.properties) { + // top-level + if (!schema.required?.find((r) => r === propertyName)) { + const schemaWithoutUnrequired = { + ...schema, + properties: { + ...schema.properties, + }, + } + delete schemaWithoutUnrequired.properties![propertyName] + + schemasWithoutUnrequired.push({ + schema: schemaWithoutUnrequired, + path: `${prefix}.${propertyName}`, + }) + } + + // recurse + const propertySchemasWithoutUnrequired = generateSchemasWithoutUnrequired( + schema.properties[propertyName], + `${prefix}.${propertyName}` + ) + + for (const propertySchemaWithoutUnrequired of propertySchemasWithoutUnrequired) { + const schemaWithoutUnrequired = { + ...schema, + properties: { + ...schema.properties, + }, + } + schemaWithoutUnrequired.properties[propertyName] = + propertySchemaWithoutUnrequired.schema + + schemasWithoutUnrequired.push({ + ...propertySchemaWithoutUnrequired, + schema: schemaWithoutUnrequired, + }) + } + } + } + + return schemasWithoutUnrequired +} diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/schemas/userType.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schemas/userType.ts similarity index 100% rename from helper/crosslab-typescript-addon/src/filters/typescript/schemas/userType.ts rename to helper/crosslab-typescript-addon/src/filterCollections/typescript/schemas/userType.ts diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/types.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/types.ts new file mode 100644 index 00000000..574d650f --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/types.ts @@ -0,0 +1,78 @@ +import { OpenAPIV3_1 } from 'openapi-types' + +/** + * This type extends a SchemaObject with the properties 'x-name', 'x-standalone', + * 'x-location' and 'x-service-name'. 'x-name' contains the formatted name of the + * schema, 'x-standalone' determines whether a validation function should be + * generated for this schema and 'x-location' contains the location of the schema + * inside of its containing document. 'x-service-name' contains the name of the + * service the schema belongs to. + */ +export type ExtendedSchema = OpenAPIV3_1.SchemaObject & { + 'x-standalone': boolean + 'x-name': string + 'x-location': string + 'x-service-name': string + 'x-schema-type': 'request' | 'response' | 'all' +} + +export type SimplifiedParameter = { + name: string + required: boolean + in: string + description?: string + schema?: OpenAPIV3_1.SchemaObject +} + +export type SimplifiedRequestBody = { + required: boolean + description?: string + schema?: OpenAPIV3_1.SchemaObject +} + +export type SimplifiedHeader = { + name: string + required: boolean + schema?: OpenAPIV3_1.SchemaObject +} + +export type SimplifiedResponse = { + status: string + description: string + schema?: OpenAPIV3_1.SchemaObject + headers?: SimplifiedHeader[] +} + +export type SimplifiedOperation = { + name: string + path: string + method: string + external: boolean + serviceName: string + operationId: string + summary: string + destructureInput: boolean + buildUrl: boolean + optionalUrl: boolean + isProxyRequest: boolean + security?: OpenAPIV3_1.SecurityRequirementObject[] + parameters?: SimplifiedParameter[] + requestBody?: SimplifiedRequestBody + responses?: SimplifiedResponse[] +} + +/** + * Interface for the property of a destructured schema. + */ +export interface DestructuredProperty { + name: string + declaration: string + required: boolean + description?: string + top: boolean +} + +/** + * Typing for destructured schemas. + */ +export type DestructuredSchema = DestructuredProperty[] diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts new file mode 100644 index 00000000..65ee7618 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts @@ -0,0 +1,58 @@ +import { formatName } from '../format' +import { DestructuredSchema, ExtendedSchema } from '../types' +import { generateTyping } from './typing' +import { OpenAPIV3_1 } from 'openapi-types' + +export function destructureSchema( + schema: OpenAPIV3_1.SchemaObject, + options?: { + prefixDirectlyResolved?: string + context?: ExtendedSchema[] + }, + first: boolean = true +): DestructuredSchema { + const destructuredSchema: DestructuredSchema = [] + + if (schema.type === 'array' && first) { + destructuredSchema.push({ + name: formatName(schema.title ?? 'default', false), + description: schema.description, + declaration: generateTyping(schema, { + inline: true, + resolveDirectly: false, + context: options?.context, + prefixDirectlyResolved: options?.prefixDirectlyResolved, + }).typeDeclaration, + required: true, + top: true, + }) + } + + if (schema.allOf) { + for (const s of schema.allOf as OpenAPIV3_1.SchemaObject[]) { + destructuredSchema.push(...destructureSchema(s, options, false)) + } + } + + if (schema.properties) { + for (const propertyName in schema.properties) { + const property = schema.properties[propertyName] as OpenAPIV3_1.SchemaObject + destructuredSchema.push({ + name: propertyName, + description: property.description, + declaration: generateTyping(property, { + inline: true, + resolveDirectly: true, + context: options?.context, + prefixDirectlyResolved: options?.prefixDirectlyResolved, + }).typeDeclaration, + required: schema.required + ? schema.required.includes(propertyName) + : false, + top: false, + }) + } + } + + return destructuredSchema +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/allOf.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/allOf.ts new file mode 100644 index 00000000..9fc7c4ee --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/allOf.ts @@ -0,0 +1,24 @@ +import { generateTyping, TypingOptions, Typing } from '../typing' +import { OpenAPIV3_1 } from 'openapi-types' + +export function handleAllOf( + schema: OpenAPIV3_1.SchemaObject, + comment: string, + options: TypingOptions +): Typing { + let type = undefined + const typeDeclarations = [] + let dependencies: Array = [] + for (const subschema of schema.allOf as Array) { + if (!type) type = subschema.type + if (type != subschema.type) throw 'Error: cannot merge types for allOf' + const td = generateTyping(subschema, options) + typeDeclarations.push(td.typeDeclaration) + dependencies = dependencies.concat(td.typeDependencies) + } + return { + typeDeclaration: typeDeclarations.join(' & '), + typeDependencies: dependencies, + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/anyOf.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/anyOf.ts new file mode 100644 index 00000000..4cbda512 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/anyOf.ts @@ -0,0 +1,21 @@ +import { generateTyping, TypingOptions, Typing } from '../typing' +import { OpenAPIV3_1 } from 'openapi-types' + +export function handleAnyOf( + schema: OpenAPIV3_1.SchemaObject, + comment: string, + options: TypingOptions +): Typing { + const typeDeclarations = [] + let dependencies: Array = [] + for (const subschema of schema.anyOf ?? []) { + const td = generateTyping(subschema, options) + typeDeclarations.push(td.typeDeclaration) + dependencies = dependencies.concat(td.typeDependencies) + } + return { + typeDeclaration: typeDeclarations.join(' | '), + typeDependencies: dependencies, + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/const.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/const.ts new file mode 100644 index 00000000..fb622386 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/const.ts @@ -0,0 +1,17 @@ +import { Typing } from '../typing' +import { OpenAPIV3_1 } from 'openapi-types' + +export function handleConst(schema: OpenAPIV3_1.SchemaObject, comment: string): Typing { + if (typeof (schema as any).const === 'string') + return { + typeDeclaration: `"${(schema as any).const}"`, + typeDependencies: [], + comment: comment, + } + else + return { + typeDeclaration: `${(schema as any).const}`, + typeDependencies: [], + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/enum.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/enum.ts new file mode 100644 index 00000000..d0d71c99 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/enum.ts @@ -0,0 +1,10 @@ +import { Typing } from '../typing' +import { OpenAPIV3_1 } from 'openapi-types' + +export function handleEnum(schema: OpenAPIV3_1.SchemaObject, comment: string): Typing { + return { + typeDeclaration: '"' + schema.enum?.join('" | "') + '"', + typeDependencies: [], + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/oneOf.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/oneOf.ts new file mode 100644 index 00000000..54cc1a48 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/keywords/oneOf.ts @@ -0,0 +1,21 @@ +import { generateTyping, TypingOptions, Typing } from '../typing' +import { OpenAPIV3_1 } from 'openapi-types' + +export function handleOneOf( + schema: OpenAPIV3_1.SchemaObject, + comment: string, + options: TypingOptions +): Typing { + const typeDeclarations = [] + let dependencies: Array = [] + for (const subschema of schema.oneOf ?? []) { + const td = generateTyping(subschema, options) + typeDeclarations.push(td.typeDeclaration) + dependencies = dependencies.concat(td.typeDependencies) + } + return { + typeDeclaration: typeDeclarations.join(' | '), + typeDependencies: dependencies, + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/array.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/array.ts new file mode 100644 index 00000000..ebc38ac0 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/array.ts @@ -0,0 +1,29 @@ +import { generateTyping, TypingOptions, Typing } from '../typing' +import { OpenAPIV3_1 } from 'openapi-types' + +export function handleArray( + schema: OpenAPIV3_1.SchemaObject, + comment: string, + options: TypingOptions +): Typing { + const td = generateTyping((schema as OpenAPIV3_1.ArraySchemaObject).items, options) + + let min = 'undefined' + let max = 'undefined' + + if (schema.minItems) min = schema.minItems.toString() + if (schema.maxItems) max = schema.maxItems.toString() + + if (schema.minItems && schema.maxItems && schema.minItems > schema.maxItems) { + throw new Error('minItems needs to be smaller than maxItems!') + } + + return { + typeDeclaration: + min !== 'undefined' || max !== 'undefined' + ? `SizedTuple<${td.typeDeclaration},${min},${max}>` + : `${td.typeDeclaration}[]`, + typeDependencies: td.typeDependencies, + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/boolean.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/boolean.ts new file mode 100644 index 00000000..97af9923 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/boolean.ts @@ -0,0 +1,9 @@ +import { Typing } from '../typing' + +export function handleBoolean(comment: string): Typing { + return { + typeDeclaration: 'boolean', + typeDependencies: [], + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/integer.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/integer.ts new file mode 100644 index 00000000..714846b3 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/integer.ts @@ -0,0 +1,9 @@ +import { Typing } from '../typing' + +export function handleInteger(comment: string): Typing { + return { + typeDeclaration: 'number', + typeDependencies: [], + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/null.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/null.ts new file mode 100644 index 00000000..f9a00dc1 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/null.ts @@ -0,0 +1,9 @@ +import { Typing } from '../typing' + +export function handleNull(comment: string): Typing { + return { + typeDeclaration: 'null', + typeDependencies: [], + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/number.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/number.ts new file mode 100644 index 00000000..781c2163 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/number.ts @@ -0,0 +1,9 @@ +import { Typing } from '../typing' + +export function handleNumber(comment: string): Typing { + return { + typeDeclaration: 'number', + typeDependencies: [], + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/object.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/object.ts new file mode 100644 index 00000000..8c57097e --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/object.ts @@ -0,0 +1,38 @@ +import { generateTyping, TypingOptions, Typing } from '../typing' +import { OpenAPIV3_1 } from 'openapi-types' + +export function handleObject( + schema: OpenAPIV3_1.SchemaObject, + comment: string, + options: TypingOptions +): Typing { + const required = schema.required ?? [] + const properties = [] + let dependencies: Array = [] + if (schema.properties) { + for (const property of Object.keys(schema.properties)) { + const td = generateTyping(schema.properties[property], options) + properties.push( + `${td.comment}${property}${required.includes(property) ? '' : '?'}: ${ + td.typeDeclaration + }` + ) + dependencies = dependencies.concat(td.typeDependencies) + } + } + if (schema.additionalProperties !== false) { + properties.push('[k: string]: unknown') + } + if (options.inline) + return { + typeDeclaration: `{${properties.join(', ')}}`, + typeDependencies: dependencies, + comment: comment, + } + else + return { + typeDeclaration: `{\n\t${properties.join('\n').replace(/\n/gi, '\n\t')}\n}`, + typeDependencies: dependencies, + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/string.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/string.ts new file mode 100644 index 00000000..23384e1e --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/types/string.ts @@ -0,0 +1,9 @@ +import { Typing } from '../typing' + +export function handleString(comment: string): Typing { + return { + typeDeclaration: 'string', + typeDependencies: [], + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts new file mode 100644 index 00000000..9993a923 --- /dev/null +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts @@ -0,0 +1,135 @@ +import { formatName } from '../format' +import { ExtendedSchema } from '../types' +import { handleAllOf } from './keywords/allOf' +import { handleAnyOf } from './keywords/anyOf' +import { handleConst } from './keywords/const' +import { handleEnum } from './keywords/enum' +import { handleOneOf } from './keywords/oneOf' +import { handleArray } from './types/array' +import { handleBoolean } from './types/boolean' +import { handleInteger } from './types/integer' +import { handleNull } from './types/null' +import { handleNumber } from './types/number' +import { handleObject } from './types/object' +import { handleString } from './types/string' +import { OpenAPIV3_1 } from 'openapi-types' + +export type TypingOptions = { + prefixDirectlyResolved?: string + inline?: boolean + resolveDirectly?: boolean + context?: ExtendedSchema[] + schemaType?: 'request' | 'response' | 'all' +} + +export type Typing = { + comment?: string + typeDeclaration: string + typeDependencies: Array +} + +export function generateTyping( + schema: OpenAPIV3_1.SchemaObject, + options?: TypingOptions +): Typing { + // set default values for options + options ??= {} + options.inline ??= false + options.resolveDirectly ??= true + options.context ??= [] + options.schemaType ??= 'all' + options.prefixDirectlyResolved ??= '' + + let comment = schema.description + ? `/**\n * ${schema.description.replace(/\n/g, '\n * ')}\n */\n` + : '' + + const contextSchema = options.context.find( + (contextSchema) => + contextSchema.title === schema.title && contextSchema['x-standalone'] + ) + + // Handle subtype and different required properties + if (options.resolveDirectly && schema.title && contextSchema) { + return resolveSchemaDirectly( + { ...schema, title: schema.title }, + contextSchema, + comment, + options + ) + } + + // Handle allOf + if (schema.allOf) return handleAllOf(schema, comment, options) + + // Handle anyOf + if (schema.anyOf) return handleAnyOf(schema, comment, options) + + // Handle oneOf + if (schema.oneOf) return handleOneOf(schema, comment, options) + + // Handle enum + if (schema.enum) return handleEnum(schema, comment) + + // Handle const + if (schema.const) return handleConst(schema, comment) + + // Handle the different possible types + switch (schema.type) { + case 'object': + return handleObject(schema, comment, options) + case 'array': + return handleArray(schema, comment, options) + case 'integer': + return handleInteger(comment) + case 'boolean': + return handleBoolean(comment) + case 'string': + return handleString(comment) + case 'null': + return handleNull(comment) + case 'number': + return handleNumber(comment) + } + + return { + typeDeclaration: 'any', + typeDependencies: [], + comment: comment, + } +} + +function resolveSchemaDirectly( + schema: OpenAPIV3_1.SchemaObject & { title: string }, + contextSchema: ExtendedSchema, + comment: string, + options: TypingOptions +) { + // check if schema has new required properties compared to + // contextSchema and if so add them via the Require type + let prefix = '' + let suffix = '' + if (options.context) { + if (schema.required) { + const contextRequired = contextSchema.required ?? [] + const newRequired = schema.required.filter( + (required) => !contextRequired.includes(required) + ) + if (newRequired.length > 0) { + prefix = 'Require<' + suffix = `, ${newRequired.map((r) => `"${r}"`).join(' | ')}>` + } + } + } + return { + typeDeclaration: + prefix + + options.prefixDirectlyResolved + + formatName(schema.title) + + (options.schemaType === 'request' ? '<"request">' : '') + + (options.schemaType === 'response' ? '<"response">' : '') + + suffix, + typeDependencies: [formatName(schema.title)], + comment: comment, + } +} diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/index.ts b/helper/crosslab-typescript-addon/src/filters/typescript/index.ts deleted file mode 100644 index 411f230c..00000000 --- a/helper/crosslab-typescript-addon/src/filters/typescript/index.ts +++ /dev/null @@ -1,517 +0,0 @@ -import { formatName, formatOperation, formatExpressPath } from './format' -import { - ExtendedSchema, - generateInvalidSchemas, - generateSchemasWithoutUnrequired, - resolveOperations, - resolveSchemas, - SimplifiedOperation, -} from './resolve' -import { destructureSchema, schemaToTypeDeclaration } from './typings' -import { validation_filter } from './validation' -import { FilterCollection } from '@cross-lab-project/openapi-codegen' -import { OpenAPIV3_1 } from 'openapi-types' -import { format } from 'prettier' - -/** - * This function defines a filter which attempts to generate the inline type - * declaration for a given schema. - * @param schema The schema for which to generate the inline type declaration. - * @returns The generated inline type declaration. - */ -function inlineTypeDeclaration_filter(schema: OpenAPIV3_1.SchemaObject) { - return schemaToTypeDeclaration(schema, { inline: true }).typeDeclaration -} - -/** - * This function defines a filter which attempts to generate the type declaration - * for a given schema. - * @param schema The schema for which to generate the type declaration. - * @returns The generated type declaration. - */ -function typeDeclaration_filter( - schema: OpenAPIV3_1.SchemaObject, - extendedSchemas: ExtendedSchema[] = [], - options?: { - prefixTypes?: string - inline?: boolean - resolveDirectly?: boolean - context?: OpenAPIV3_1.SchemaObject[] - } -) { - return schemaToTypeDeclaration(schema, { ...options, context: extendedSchemas }) - .typeDeclaration -} - -/** - * This function defines a filter which attempts to find the type dependencies for - * a given schema. - * @param schema The schema for which to find the type dependencies. - * @returns The found type dependencies. - */ -function typeDependencies_filter( - schema: OpenAPIV3_1.SchemaObject, - extendedSchemas: ExtendedSchema[] = [] -) { - return schemaToTypeDeclaration(schema, { context: extendedSchemas }).typeDependencies -} - -/** - * This function defines a filter which generates the typings for all provided - * schemas which have the property 'x-standalone' set to true. - * @param extendedSchemas The schemas for which to generate the typings. - * @returns The typings of the schemas. - */ -function standaloneTypings_filter(extendedSchemas: ExtendedSchema[]) { - const standaloneSchemas = extendedSchemas.filter( - (extendedSchema) => - extendedSchema['x-standalone'] && extendedSchema['x-schema-type'] === 'all' - ) - - const mappedStandaloneSchemas = standaloneSchemas.map((extendedSchema) => { - const requestSchema = extendedSchemas.find( - (es) => es['x-location'] === extendedSchema['x-location'] + '_request' - ) - const responseSchema = extendedSchemas.find( - (es) => es['x-location'] === extendedSchema['x-location'] + '_response' - ) - if (!requestSchema || !responseSchema) - throw new Error('Could not find request-/response-schema') - return { - all: extendedSchema, - request: requestSchema, - response: responseSchema, - } - }) - - return mappedStandaloneSchemas - .map((schemas) => { - const name = schemas.all.title - ? formatName(schemas.all.title) - : 'MISSING_NAME' - const tdAll = schemaToTypeDeclaration(schemas.all, { - inline: false, - resolveDirectly: false, - context: standaloneSchemas, - }) - const tdRequest = schemaToTypeDeclaration(schemas.request, { - inline: false, - resolveDirectly: false, - context: standaloneSchemas, - }) - const tdResponse = schemaToTypeDeclaration(schemas.response, { - inline: false, - resolveDirectly: false, - context: standaloneSchemas, - }) - return ` - ${tdAll.comment}export type ${name} = T extends "all" - ? ${tdAll.typeDeclaration} - : T extends "request" - ? ${tdRequest.typeDeclaration} - : T extends "response" - ? ${tdResponse.typeDeclaration} - : never - ` - }) - .join('\n\n') -} - -/** - * This function defines a filter which flattens an array. - * @param array The array to be flattened. - * @returns The flattened array. - */ -function flatten_filter(array: any[]): any[] { - const newArray = [] - for (const item of array) { - if (Array.isArray(item)) newArray.push(...flatten_filter(item)) - else newArray.push(item) - } - return newArray -} - -/** - * This function defines a filter which filters duplicate values from an array. - * @param array The array to be filtered. - * @returns The array without duplicate values. - */ -function unique_filter(array: any[]): any[] { - return array.filter((v, i, s) => s.indexOf(v) === i) -} - -/** - * This function defines a filter which attempts to resolve the schemas of a given - * OpenAPI document. - * @param api The OpenAPI document for which to resolve the schemas. - * @param isService - * If true the UserType schema is added and method path will be used for - * naming. Otherwise the operationId will be used for naming. - * @returns - * The resolved schemas with additional properties 'x-name', 'x-standalone' - * and 'x-location'. - */ -function resolveSchemas_filter( - api: OpenAPIV3_1.Document, - isService = true -): ExtendedSchema[] { - return resolveSchemas(api, isService) -} - -/** - * This function defines a filter which attempts to resolve the operations of a - * given OpenAPI document. - * @param api The OpenAPI document for which to resolve the operations. - * @returns The resolved operations. - */ -function resolveOperations_filter(api: OpenAPIV3_1.Document): SimplifiedOperation[] { - return resolveOperations(api) -} - -/** - * This function defines a filter which capitalizes the first letter of a given string. - * @param s The string to be capitalized. - * @returns The capitalized string. - */ -function capitalize_filter(s: string): string { - return s.charAt(0).toUpperCase() + s.slice(1) -} - -/** - * This function defines a filter which adds quotation marks to the elements of a - * given string array. - * @param arr The string array for which to add quotation marks to its elements. - * @returns The string array with quotation marks around its elements. - */ -function strings_filter(arr: string[]): string[] { - return arr.map((s) => `"${s}"`) -} - -/** - * This function defines a filter which attempts to stringify a given object. - * @param o The object to be stringified. - * @param indentation The indentation to be used during JSON.stringify. - * @returns The stringified object. - */ -function stringify_filter(o: any, indentation = 0): string { - return JSON.stringify(o, null, indentation) -} - -/** - * This function defines a filter which attempts to return an array which only - * contains the requested attribute as its elements. - * @param arr The array to be filtered. - * @param attributeName The name of the attribute. - */ -function attribute_filter(arr: any[], attributeName: string): any[] { - return arr.map((o) => o[attributeName]) -} - -/** - * This function defines a filter which attempts to sort the given array into - * subarrays using the provided attribute name. - * @param arr The array to be sorted. - * @param attributeName The name of the attribute to sort the array by. - * @returns A map containing the subarray for every value of the attribute. - */ -function sort_by_attribute_filter( - arr: any[], - attributeName: string -): { - [k: string]: any[] -} { - const sorted: { - [k: string]: any[] - } = {} - - for (const item of arr) { - if (!sorted[item[attributeName]]) sorted[item[attributeName]] = [] - sorted[item[attributeName]].push(item) - } - - delete sorted['undefined'] - - return sorted -} - -/** - * This function defines a filter that applies prettier to a string. - * @param string The string to apply prettier on. - * @returns The formatted string - */ -function prettier_filter(string: string) { - return format(string, { parser: 'typescript', tabWidth: 4, singleQuote: true }) -} - -/** - * This function defines a filter that checks if a given string ends with the - * provided search string. - * @param string The string to be checked. - * @param searchString The search string. - * @returns True if the given string ends with the search string, else false. - */ -function endswith_filter(string: string, searchString: string) { - return string.endsWith(searchString as string) -} - -/** - * This function defines a filter that checks if a given string starts with the - * provided search string. - * @param string The string to be checked. - * @param searchString The search string. - * @returns True if the given string ends with the search string, else false. - */ -function startswith_filter(string: string, searchString: string) { - return string.startsWith(searchString as string) -} - -/** - * This function defines a filter that splits a given string into an array of - * substrings divided by the provided split string. - * @param string The string to be split. - * @param splitString The split string. - * @example - * ``` - * "This is a test" | split(" ") = ["This", "is", "a", "test"] - * ``` - * @returns The array of substrings. - */ -function split_filter(string: string, splitString: string) { - return string.split(splitString) -} - -/** - * This function defines a filter that attempts to destructure a schema. - * @param schema The schema to be destructured. - * @param options.prefixTypes A prefix to be appended to property types. - * @param options.context List of schemas used to resolve property types. - * @returns The destructured schema - */ -function destructureSchema_filter( - schema: OpenAPIV3_1.SchemaObject, - options?: { - prefixTypes?: string - context?: OpenAPIV3_1.SchemaObject[] - } -) { - return destructureSchema(schema, options) -} - -/** - * This function defines a filter that attempts to delete a property of an object. - * @param object The object from which to delete the property. - * @param key The key of the property to be deleted. - */ -function delete_filter(object: any, key: string) { - delete object[key] -} - -/** - * This function defines a filter that attempts to clone an object. - * @param object The object to be cloned. - */ -function clone_filter(object: any) { - return JSON.parse(JSON.stringify(object)) -} - -/** - * This function gets an invalid status code for an operation. - * @param operation The operation for which to get the invalid status code. - * @returns An invalid status code for the provided operation. - */ -function getInvalidStatusCode_filter(operation: SimplifiedOperation) { - const invalidStatusCodes: number[] = [] - - for (let i = 100; i < 600; i++) { - invalidStatusCodes.push(i) - } - - for (const response of operation.responses ?? []) { - if (response.status.endsWith('XX')) { - const start = parseInt(response.status.replace(/X/g, '0')) - for (let i = start; i < start + 100; i++) { - const foundIndex = invalidStatusCodes.findIndex( - (statusCode) => statusCode === i - ) - if (foundIndex > -1) invalidStatusCodes.splice(foundIndex, 1) - } - } else { - const parsedStatusCode = parseInt(response.status) - const foundIndex = invalidStatusCodes.findIndex( - (statusCode) => statusCode === parsedStatusCode - ) - if (foundIndex > -1) invalidStatusCodes.splice(foundIndex, 1) - } - } - - return invalidStatusCodes.length > 0 ? invalidStatusCodes[0] : undefined -} - -function includes_filter(string: string, searchString: string) { - return string.includes(searchString) -} - -function addProperty_filter(obj: { [k: string]: any }, propertyName: string, value: any) { - obj[propertyName] = value -} - -function append_filter(array: any[], value: any) { - array.push(value) -} - -function getPossibleScopeCombinations( - security?: OpenAPIV3_1.SecurityRequirementObject[] -) { - const possibleCombinations: [string, string][][] = [] - for (const securityRequirement of security ?? []) { - let combinations: [string, string][][] = [] - for (const key in securityRequirement) { - const scopes = securityRequirement[key] - if (combinations.length === 0) { - for (const scope of scopes) { - combinations.push([[key, scope]]) - } - } else { - for (const scope of scopes) { - combinations = combinations.map((comb) => [...comb, [key, scope]]) - } - } - } - possibleCombinations.push(...combinations) - } - - return possibleCombinations -} - -/** - * The filter collection for typescript. - */ -export const TypeScriptFilterCollection: FilterCollection = { - name: 'typescript', - filters: [ - { - name: 'inlineTypeDeclaration', - function: inlineTypeDeclaration_filter, - }, - { - name: 'typeDeclaration', - function: typeDeclaration_filter, - }, - { - name: 'resolveSchemas', - function: resolveSchemas_filter, - }, - { - name: 'standaloneTypings', - function: standaloneTypings_filter, - }, - { - name: 'formatMethodPath', - function: formatOperation, - }, - { - name: 'typeDependencies', - function: typeDependencies_filter, - }, - { - name: 'flatten', - function: flatten_filter, - }, - { - name: 'unique', - function: unique_filter, - }, - { - name: 'validation', - function: validation_filter, - }, - { - name: 'cap', - function: capitalize_filter, - }, - { - name: 'resolveOperations', - function: resolveOperations_filter, - }, - { - name: 'expressPath', - function: formatExpressPath, - }, - { - name: 'formatName', - function: formatName, - }, - { - name: 'strings', - function: strings_filter, - }, - { - name: 'stringify', - function: stringify_filter, - }, - { - name: 'attribute', - function: attribute_filter, - }, - { - name: 'sortByAttribute', - function: sort_by_attribute_filter, - }, - { - name: 'prettier', - function: prettier_filter, - }, - { - name: 'endswith', - function: endswith_filter, - }, - { - name: 'destructureSchema', - function: destructureSchema_filter, - }, - { - name: 'split', - function: split_filter, - }, - { - name: 'startswith', - function: startswith_filter, - }, - { - name: 'delete', - function: delete_filter, - }, - { - name: 'clone', - function: clone_filter, - }, - { - name: 'generateInvalidSchemas', - function: generateInvalidSchemas, - }, - { - name: 'generateSchemasWithoutUnrequired', - function: generateSchemasWithoutUnrequired, - }, - { - name: 'getInvalidStatusCode', - function: getInvalidStatusCode_filter, - }, - { - name: 'includes', - function: includes_filter, - }, - { - name: 'addProperty', - function: addProperty_filter, - }, - { - name: 'append', - function: append_filter, - }, - { - name: 'possibleScopeCombinations', - function: getPossibleScopeCombinations, - }, - ], -} diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts b/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts deleted file mode 100644 index 75cc5fa0..00000000 --- a/helper/crosslab-typescript-addon/src/filters/typescript/resolve.ts +++ /dev/null @@ -1,699 +0,0 @@ -import { formatName, formatOperation } from './format' -import { userTypeSchema } from './schemas/userType' -import { OpenAPIV3_1 } from 'openapi-types' - -/** - * This type extends a SchemaObject with the properties 'x-name', 'x-standalone', - * 'x-location' and 'x-service-name'. 'x-name' contains the formatted name of the - * schema, 'x-standalone' determines whether a validation function should be - * generated for this schema and 'x-location' contains the location of the schema - * inside of its containing document. 'x-service-name' contains the name of the - * service the schema belongs to. - */ -export type ExtendedSchema = OpenAPIV3_1.SchemaObject & { - 'x-standalone': boolean - 'x-name': string - 'x-location': string - 'x-service-name': string - 'x-schema-type': 'request' | 'response' | 'all' -} - -type SimplifiedParameter = { - name: string - required: boolean - in: string - description?: string - schema?: OpenAPIV3_1.SchemaObject -} - -type SimplifiedRequestBody = { - required: boolean - description?: string - schema?: OpenAPIV3_1.SchemaObject -} - -type SimplifiedHeader = { - name: string - required: boolean - schema?: OpenAPIV3_1.SchemaObject -} - -type SimplifiedResponse = { - status: string - description: string - schema?: OpenAPIV3_1.SchemaObject - headers?: SimplifiedHeader[] -} - -export type SimplifiedOperation = { - name: string - path: string - method: string - external: boolean - serviceName: string - operationId: string - summary: string - destructureInput: boolean - buildUrl: boolean - optionalUrl: boolean - isProxyRequest: boolean - security?: OpenAPIV3_1.SecurityRequirementObject[] - parameters?: SimplifiedParameter[] - requestBody?: SimplifiedRequestBody - responses?: SimplifiedResponse[] -} - -/** - * This function tries to resolve the Operations of a given OpenAPI document. - * @param api The OpenAPI document for which to resolve the Operations. - * @returns The resolved Operations. - */ -export function resolveOperations(api: OpenAPIV3_1.Document): SimplifiedOperation[] { - const simplifiedPathItems: SimplifiedOperation[] = [] - - // Search for PathItems in paths - if (api.paths) { - for (const path of Object.keys(api.paths)) { - const pathItem = api.paths[path] as OpenAPIV3_1.PathItemObject - for (const method of Object.keys(pathItem)) { - const operation = pathItem[ - method as OpenAPIV3_1.HttpMethods - ] as OpenAPIV3_1.OperationObject - - // Create SimplifiedOperation with known properties - const simplifiedOperation: SimplifiedOperation = { - name: formatOperation(path, method), - path: path, - method: method, - serviceName: (operation as any)['x-service-name'], - operationId: operation.operationId ?? '', - security: operation.security, - summary: operation.summary ?? '', - external: (operation as any)['x-internal'] ? false : true, - destructureInput: (operation as any)['x-destructure-input'] ?? false, - buildUrl: (operation as any)['x-build-url'] ?? false, - optionalUrl: (operation as any)['x-optional-url'] ?? false, - isProxyRequest: (operation as any)['x-proxy-request'] ?? false, - } - - // Search for parameters to add - const parameters = operation.parameters as - | OpenAPIV3_1.ParameterObject[] - | undefined - if (parameters) { - for (const parameter of parameters) { - if (!simplifiedOperation.parameters) - simplifiedOperation.parameters = [] - const simplifiedParameter: SimplifiedParameter = { - name: parameter.name, - required: parameter.required ?? false, - in: parameter.in, - description: parameter.description, - schema: parameter.schema as - | OpenAPIV3_1.SchemaObject - | undefined, - } - simplifiedOperation.parameters.push(simplifiedParameter) - } - } - - // Search for requestBody to add - const requestBody = operation.requestBody as - | OpenAPIV3_1.RequestBodyObject - | undefined - if (requestBody) { - simplifiedOperation.requestBody = { - description: requestBody.description, - required: requestBody.required ?? false, - } - const content = requestBody.content - const schema = content['application/json'].schema - if (schema) { - simplifiedOperation.requestBody.schema = schema - } - } - - // Search for responses to add - const responses = operation.responses as - | OpenAPIV3_1.ResponsesObject - | undefined - for (const status in responses) { - if (!simplifiedOperation.responses) simplifiedOperation.responses = [] - const response = responses[status] as OpenAPIV3_1.ResponseObject - const simplifiedResponse: SimplifiedResponse = { - status: status, - description: response.description, - } - // Add schema of response if present - if ('content' in response) { - const content = response.content - if (content) { - const schema = content['application/json'].schema - if (schema) { - simplifiedResponse.schema = schema - } - } - } - // Add headers of response if present - if (response.headers) { - simplifiedResponse.headers = [] - for (const headerName in response.headers) { - const header = response.headers[ - headerName - ] as OpenAPIV3_1.HeaderObject - simplifiedResponse.headers.push({ - name: formatName(headerName), - required: header.required ?? false, - schema: header.schema as - | OpenAPIV3_1.SchemaObject - | undefined, - }) - } - } - simplifiedOperation.responses.push(simplifiedResponse) - } - - simplifiedPathItems.push(simplifiedOperation) - } - } - } - - return simplifiedPathItems -} - -/** - * This function tries to resolve the Schemas of a given OpenAPI document. - * @param api The OpenAPI document for which to resolve the Schemas. - * @param isService - * If true the UserType schema is added and method path will be used for - * naming. Otherwise the operationId will be used for naming. - * @returns - * The resolved Schemas with additional properties 'x-name', 'x-standalone' - * and 'x-location' - */ -export function resolveSchemas( - api: OpenAPIV3_1.Document, - isService = true -): ExtendedSchema[] { - const extendedSchemas: ExtendedSchema[] = [] - - // Add UserType schema - if (isService) - extendedSchemas.push({ - ...userTypeSchema, - 'x-standalone': true, - 'x-name': 'UserType', - 'x-location': `#/components/schemas/user_type`, - 'x-service-name': 'Utility', - 'x-schema-type': 'all', - }) - - // Search in components - if (api.components) { - // Search for schemas in components - if (api.components.schemas) { - for (const schemaName in api.components.schemas) { - const name = formatName( - api.components.schemas[schemaName].title ?? 'MISSING' - ) - extendedSchemas.push({ - ...api.components.schemas[schemaName], - 'x-standalone': true, - 'x-name': name, - 'x-location': `#/components/schemas/${schemaName}`, - 'x-service-name': (api.components.schemas[schemaName] as any)[ - 'x-service-name' - ], - 'x-schema-type': 'all', - }) - } - } - // Search for parameters in components - if (api.components.parameters) { - for (const parameterName in api.components.parameters) { - const parameter = api.components.parameters[ - parameterName - ] as OpenAPIV3_1.ParameterObject - const schema = parameter.schema as OpenAPIV3_1.SchemaObject - extendedSchemas.push({ - ...schema, - 'x-standalone': false, - 'x-name': formatName(parameter.name), - 'x-location': `#/components/parameters/${parameterName}/schema`, - 'x-service-name': (schema as any)['x-service-name'], - 'x-schema-type': 'all', - }) - } - } - } - - // Search in paths - if (api.paths) { - for (const path of Object.keys(api.paths)) { - const pathItem = api.paths[path] as OpenAPIV3_1.PathItemObject - for (const method of Object.keys(pathItem)) { - const operation = pathItem[ - method as OpenAPIV3_1.HttpMethods - ] as OpenAPIV3_1.OperationObject - const requestBody = operation.requestBody as - | OpenAPIV3_1.RequestBodyObject - | undefined - - // Add requestBody schema if present - if (requestBody) { - const content = requestBody.content - const schema = content['application/json'].schema - if (schema) { - extendedSchemas.push({ - ...schema, - 'x-standalone': false, - 'x-name': isService - ? formatOperation(path, method) + 'RequestBody' - : formatName(operation.operationId ?? '', false) + 'Body', - 'x-location': `#/paths/${path}/${method}/requestBody/content/application/json/schema`, - 'x-service-name': (operation as any)['x-service-name'], - 'x-schema-type': 'all', - }) - } - } - - // Search for response schemas - const responses = operation.responses - for (const status in responses) { - const response = responses[status] as OpenAPIV3_1.ResponseObject - if ('content' in response) { - const content = response.content - if (content) { - const schema = content['application/json'].schema - if (schema) { - extendedSchemas.push({ - ...schema, - 'x-standalone': false, - 'x-name': isService - ? formatOperation(path, method) + - 'Response' + - status - : formatName(operation.operationId ?? '', false) + - 'Response' + - status, - 'x-location': `#/paths/${path}/${method}/responses/${status}/content/application/json/schema`, - 'x-service-name': (operation as any)[ - 'x-service-name' - ], - 'x-schema-type': 'all', - }) - } - } - } - if (response.headers) { - for (const headerName in response.headers) { - const schema = ( - response.headers[headerName] as OpenAPIV3_1.HeaderObject - ).schema - if (schema) { - extendedSchemas.push({ - ...schema, - 'x-standalone': false, - 'x-name': isService - ? formatOperation(path, method) + - 'Header' + - formatName(headerName) - : formatName(operation.operationId ?? '', false) + - formatName(headerName), - 'x-location': `#/paths/${path}/${method}/responses/${status}/headers/${headerName}/schema`, - 'x-service-name': (operation as any)[ - 'x-service-name' - ], - 'x-schema-type': 'all', - }) - } - } - } - } - } - } - } - - const _extendedSchemas = JSON.parse( - JSON.stringify(extendedSchemas) - ) as ExtendedSchema[] - - for (const extendedSchema of _extendedSchemas) { - const readonlyRegex = /"[^\"]*?":{[^{}]*?"readOnly":true/gms - const writeonlyRegex = /"[^\"]*?":{[^{}]*?"writeOnly":true/gms - - const stringifiedExtendedSchema = JSON.stringify(extendedSchema) - - const requestRegexMatches = stringifiedExtendedSchema.matchAll(readonlyRegex) - const requestMatches = [] - for (const match of requestRegexMatches) { - let index = match.index ?? 0 - let open = 0 - let started = false - - while (!started || open !== 0) { - if (stringifiedExtendedSchema.at(index) === '{') { - started = true - open++ - } else if (stringifiedExtendedSchema.at(index) === '}') { - open-- - } - index++ - } - - requestMatches.push(stringifiedExtendedSchema.slice(match.index ?? 0, index)) - } - - const responseRegexMatches = stringifiedExtendedSchema.matchAll(writeonlyRegex) - const responseMatches = [] - for (const match of responseRegexMatches) { - let index = match.index ?? 0 - let open = 0 - let started = false - - while (!started || open !== 0) { - if (stringifiedExtendedSchema.at(index) === '{') { - started = true - open++ - } else if (stringifiedExtendedSchema.at(index) === '}') { - open-- - } - index++ - } - - responseMatches.push(stringifiedExtendedSchema.slice(match.index ?? 0, index)) - } - - const stringifiedRequestSchema = stringifiedExtendedSchema - .replace( - RegExp( - `(?:${requestMatches - .map((match) => match.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')) - .join('|')})`, - 'gms' - ), - '' - ) - .replace(/,,+/g, ',') - .replace(/,}/g, '}') - .replace(/{,/g, '{') - .replace(/"\$ref":"(.*?)"/g, '"$ref":"$1_request"') - const stringifiedResponseSchema = stringifiedExtendedSchema - .replace( - RegExp( - `(?:${responseMatches - .map((match) => match.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')) - .join('|')})`, - 'gms' - ), - '' - ) - .replace(/,,+/g, ',') - .replace(/,}/g, '}') - .replace(/{,/g, '{') - .replace(/"\$ref":"(.*?)"/g, '"$ref":"$1_response"') - - const requestSchema = JSON.parse(stringifiedRequestSchema) as ExtendedSchema - const responseSchema = JSON.parse(stringifiedResponseSchema) as ExtendedSchema - - requestSchema['x-schema-type'] = 'request' - responseSchema['x-schema-type'] = 'response' - - requestSchema['x-name'] += 'Request' - responseSchema['x-name'] += 'Response' - - requestSchema['x-location'] += '_request' - responseSchema['x-location'] += '_response' - - extendedSchemas.push(...[requestSchema, responseSchema]) - } - - return extendedSchemas -} - -/** - * This function attempts to generate invalid versions of a given schema by recursively removing - * required attributes or replacing them with invalid types / formats. - * @param schema The schema to use as a template. - * @param prefix A prefix to generate the path to the removed property. - * @returns A list of invalid versions of the template schema with the path of the removed property. - */ -export function generateInvalidSchemas( - schema: OpenAPIV3_1.SchemaObject, - prefix = 'schema' -): { - schema: OpenAPIV3_1.SchemaObject - path: string - operation: 'remove' | 'change-type' | 'remove-format' | 'remove-enum' | 'negate-type' -}[] { - const invalidSchemas: ReturnType = [] - - const anySchemas: OpenAPIV3_1.SchemaObject[] = [ - { - type: 'array', - items: {}, - }, - { - type: 'boolean', - }, - { - type: 'integer', - }, - { - type: 'null', - }, - { - type: 'number', - }, - { - type: 'object', - }, - { - type: 'string', - }, - ] - - if (schema.allOf) { - for (const [index, subSchema] of schema.allOf.entries()) { - const invalidSubSchemas = generateInvalidSchemas( - subSchema, - `${prefix}.allOf[${index}]` - ) - invalidSchemas.push(...invalidSubSchemas) - } - } - - if (schema.anyOf) { - for (const [index, subSchema] of schema.anyOf.entries()) { - const invalidSubSchemas = generateInvalidSchemas( - subSchema, - `${prefix}.allOf[${index}]` - ) - invalidSchemas.push(...invalidSubSchemas) - } - } - - if (schema.oneOf) { - for (const [index, subSchema] of schema.oneOf.entries()) { - const invalidSubSchemas = generateInvalidSchemas( - subSchema, - `${prefix}.allOf[${index}]` - ) - invalidSchemas.push(...invalidSubSchemas) - } - } - - // remove format - if (schema.format) { - const invalidSchema = { - ...schema, - } - delete invalidSchema.format - - invalidSchemas.push({ - schema: invalidSchema, - path: `${prefix}`, - operation: 'remove-format', - }) - } - - // remove enum - if (schema.enum) { - const invalidSchema = { - ...schema, - } - delete invalidSchema.enum - - invalidSchemas.push({ - schema: invalidSchema, - path: `${prefix}`, - operation: 'remove-enum', - }) - } - - // change type - if (schema.type) { - invalidSchemas.push({ - schema: { - anyOf: [...anySchemas.filter((s) => s.type !== schema.type)], - }, - path: `${prefix}`, - operation: 'change-type', - }) - } - - invalidSchemas.push({ - schema: { - not: schema, - }, - path: `${prefix}`, - operation: 'negate-type', - }) - - switch (schema.type) { - case 'object': - if (schema.properties) { - // remove required properties - if (schema.required) { - for (const requiredProperty of schema.required) { - const removedSchema = { - ...schema, - properties: { - ...schema.properties, - }, - } - removedSchema.required = removedSchema.required?.filter( - (r) => r !== requiredProperty - ) - delete removedSchema.properties![requiredProperty] - - invalidSchemas.push({ - schema: removedSchema, - path: `${prefix}.${requiredProperty}`, - operation: 'remove', - }) - } - } - - // recurse into properties - for (const propertyName in schema.properties) { - const property = schema.properties[ - propertyName - ] as OpenAPIV3_1.SchemaObject - - const invalidPropertySchemas = generateInvalidSchemas( - property, - `${prefix}.${propertyName}` - ) - - for (const invalidPropertySchema of invalidPropertySchemas) { - const invalidSchema = { - ...schema, - properties: { - ...schema.properties, - }, - } - invalidSchema.properties[propertyName] = - invalidPropertySchema.schema - - if ( - invalidPropertySchema.operation !== 'remove' && - !invalidSchema.required?.find((r) => r === propertyName) - ) { - if (!invalidSchema.required) - invalidSchema.required = [propertyName] - else invalidSchema.required.push(propertyName) - } - - invalidSchemas.push({ - ...invalidPropertySchema, - schema: invalidSchema, - }) - } - } - } - break - case 'array': - // eslint-disable-next-line no-case-declarations - const invalidItemsSchemas = generateInvalidSchemas( - schema.items, - `${prefix}.items` - ) - for (const invalidItemsSchema of invalidItemsSchemas) { - const currentSchema = schema - invalidSchemas.push({ - ...invalidItemsSchema, - schema: { - ...currentSchema, - items: invalidItemsSchema.schema, - }, - }) - } - break - default: - break - } - - return invalidSchemas -} - -/** - * Generates versions of a given schema without one of the unrequired properties. - * @param schema The schema for which to generate the versions. - * @param prefix A prefix to generate the path to the removed property. - * @returns A list of schemas with each one missing an unrequired property. - */ -export function generateSchemasWithoutUnrequired( - schema: OpenAPIV3_1.SchemaObject, - prefix = 'schema' -): { - schema: OpenAPIV3_1.SchemaObject - path: string -}[] { - const schemasWithoutUnrequired: ReturnType = - [] - - if (schema.properties) { - for (const propertyName in schema.properties) { - // top-level - if (!schema.required?.find((r) => r === propertyName)) { - const schemaWithoutUnrequired = { - ...schema, - properties: { - ...schema.properties, - }, - } - delete schemaWithoutUnrequired.properties![propertyName] - - schemasWithoutUnrequired.push({ - schema: schemaWithoutUnrequired, - path: `${prefix}.${propertyName}`, - }) - } - - // recurse - const propertySchemasWithoutUnrequired = generateSchemasWithoutUnrequired( - schema.properties[propertyName], - `${prefix}.${propertyName}` - ) - - for (const propertySchemaWithoutUnrequired of propertySchemasWithoutUnrequired) { - const schemaWithoutUnrequired = { - ...schema, - properties: { - ...schema.properties, - }, - } - schemaWithoutUnrequired.properties[propertyName] = - propertySchemaWithoutUnrequired.schema - - schemasWithoutUnrequired.push({ - ...propertySchemaWithoutUnrequired, - schema: schemaWithoutUnrequired, - }) - } - } - } - - return schemasWithoutUnrequired -} diff --git a/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts b/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts deleted file mode 100644 index 461d96d0..00000000 --- a/helper/crosslab-typescript-addon/src/filters/typescript/typings.ts +++ /dev/null @@ -1,318 +0,0 @@ -/* eslint-disable no-case-declarations */ -import { formatName } from './format' -import { OpenAPIV3_1 } from 'openapi-types' - -/** - * Interface for the property of a destructured schema. - */ -interface DestructuredProperty { - name: string - declaration: string - required: boolean - description?: string - top: boolean -} - -/** - * Typing for destructured schemas. - */ -type DestructuredSchema = DestructuredProperty[] - -/** - * Destructures a schema. - * @param schema The schema to be destructured. - * @param options.context - * Other schemas which can be used to determine a changed required property. - * @param options.prefixTypes - * The prefix that should be appended to directly resolved types. - * @returns Properties of provided schema. - */ -export function destructureSchema( - schema: OpenAPIV3_1.SchemaObject, - options?: { - prefixTypes?: string - context?: OpenAPIV3_1.SchemaObject[] - }, - first = true -): DestructuredSchema { - const destructuredSchema: DestructuredSchema = [] - - if (schema.type === 'array' && first) { - destructuredSchema.push({ - name: formatName(schema.title ?? 'default', false), - description: schema.description, - declaration: schemaToTypeDeclaration(schema, { - inline: true, - resolveDirectly: false, - context: options?.context, - prefixTypes: options?.prefixTypes, - }).typeDeclaration, - required: true, - top: true, - }) - } - - if (schema.allOf) { - for (const s of schema.allOf as OpenAPIV3_1.SchemaObject[]) { - destructuredSchema.push(...destructureSchema(s, options, false)) - } - } - - if (schema.properties) { - for (const propertyName in schema.properties) { - const property = schema.properties[propertyName] as OpenAPIV3_1.SchemaObject - destructuredSchema.push({ - name: propertyName, - description: property.description, - declaration: schemaToTypeDeclaration(property, { - inline: true, - resolveDirectly: true, - context: options?.context, - prefixTypes: options?.prefixTypes, - }).typeDeclaration, - required: schema.required - ? schema.required.includes(propertyName) - : false, - top: false, - }) - } - } - - return destructuredSchema -} - -/** - * resolves the type declaration and type dependencies of a schema. - * @param schema - * SchemaObject for which to resolve type declaration and type dependencies. - * @param options.inline - * Determines if the output should be in one line. - * @param options.resolveDirectly - * Determines if a schema with a title should be resolved directly. - * @param options.context - * Other schemas which can be used to determine a changed required property. - * @param options.prefixTypes - * The prefix that should be appended to directly resolved types. - * @returns comment, type declaration and type dependencies. - */ -export function schemaToTypeDeclaration( - schema: OpenAPIV3_1.SchemaObject, - options?: { - prefixTypes?: string - inline?: boolean - resolveDirectly?: boolean - context?: OpenAPIV3_1.SchemaObject[] - schemaType?: 'request' | 'response' | 'all' - } -): { - comment?: string - typeDeclaration: string - typeDependencies: Array -} { - // set default values for options - options = options ?? {} - options.inline = options.inline ?? false - options.resolveDirectly = options.resolveDirectly ?? true - options.context = options.context ?? [] - options.schemaType = options.schemaType ?? 'all' - options.prefixTypes = options.prefixTypes ?? '' - - const comment = schema.description - ? `/**\n * ${schema.description.replace(/\n/g, '')}\n */\n` - : '' - - // Handle subtype and different required properties - if (options.resolveDirectly && schema.title) { - let prefix = '' - let suffix = '' - if (options.context) { - if (schema.required) { - const contextSchema = options.context.find((s) => { - return s.title === schema.title - }) - const contextRequired = contextSchema?.required ?? [] - const newRequired = schema.required.filter( - (r) => !contextRequired.includes(r) - ) - if (newRequired.length > 0) { - prefix = 'Require<' - suffix = `, ${newRequired.map((r) => `"${r}"`).join(' | ')}>` - } - } - } - if ( - options.context.find( - (s) => s.title === schema.title && (s as any)['x-standalone'] - ) - ) { - return { - typeDeclaration: - prefix + - options.prefixTypes + - formatName(schema.title) + - (options.schemaType === 'request' ? '<"request">' : '') + - (options.schemaType === 'response' ? '<"response">' : '') + - suffix, - typeDependencies: [formatName(schema.title)], - comment: comment, - } - } - } - - // Handle allOf - if (schema.allOf) { - let type = undefined - const typeDeclarations = [] - let dependencies: Array = [] - for (const subschema of schema.allOf as Array) { - if (!type) type = subschema.type - if (type != subschema.type) throw 'Error: cannot merge types for allOf' - const td = schemaToTypeDeclaration(subschema, options) - typeDeclarations.push(td.typeDeclaration) - dependencies = dependencies.concat(td.typeDependencies) - } - return { - typeDeclaration: typeDeclarations.join(' & '), - typeDependencies: dependencies, - comment: comment, - } - } - - // Handle anyOf - if (schema.anyOf) { - const typeDeclarations = [] - let dependencies: Array = [] - for (const subschema of schema.anyOf) { - const td = schemaToTypeDeclaration(subschema, options) - typeDeclarations.push(td.typeDeclaration) - dependencies = dependencies.concat(td.typeDependencies) - } - return { - typeDeclaration: typeDeclarations.join(' | '), - typeDependencies: dependencies, - comment: comment, - } - } - - // Handle oneOf - if (schema.oneOf) { - const typeDeclarations = [] - let dependencies: Array = [] - for (const subschema of schema.oneOf) { - const td = schemaToTypeDeclaration(subschema, options) - typeDeclarations.push(td.typeDeclaration) - dependencies = dependencies.concat(td.typeDependencies) - } - return { - typeDeclaration: typeDeclarations.join(' | '), - typeDependencies: dependencies, - comment: comment, - } - } - - // Handle enum - if (schema.enum) { - return { - typeDeclaration: '"' + schema.enum.join('" | "') + '"', - typeDependencies: [], - comment: comment, - } - } - - // Handle const - if ((schema as any).const) { - if (typeof (schema as any).const === 'string') - return { - typeDeclaration: `"${(schema as any).const}"`, - typeDependencies: [], - comment: comment, - } - else - return { - typeDeclaration: `${(schema as any).const}`, - typeDependencies: [], - comment: comment, - } - } - - // Handle the different possible types - switch (schema.type) { - case 'object': - const required = schema.required ?? [] - const properties = [] - let dependencies: Array = [] - if (schema.properties) { - for (const property of Object.keys(schema.properties)) { - const td = schemaToTypeDeclaration( - schema.properties[property], - options - ) - properties.push( - `${td.comment}${property}${ - required.includes(property) ? '' : '?' - }: ${td.typeDeclaration}` - ) - dependencies = dependencies.concat(td.typeDependencies) - } - } - if (schema.additionalProperties !== false) { - properties.push('[k: string]: unknown') - } - if (options.inline) - return { - typeDeclaration: `{${properties.join(', ')}}`, - typeDependencies: dependencies, - comment: comment, - } - else - return { - typeDeclaration: `{\n\t${properties - .join('\n') - .replace(/\n/gi, '\n\t')}\n}`, - typeDependencies: dependencies, - comment: comment, - } - - case 'array': - const td = schemaToTypeDeclaration( - (schema as OpenAPIV3_1.ArraySchemaObject).items, - options - ) - - let min = 'undefined' - let max = 'undefined' - - if (schema.minItems) min = schema.minItems.toString() - if (schema.maxItems) max = schema.maxItems.toString() - - if (schema.minItems && schema.maxItems && schema.minItems > schema.maxItems) { - throw new Error('minItems needs to be smaller than maxItems!') - } - - return { - typeDeclaration: - min !== 'undefined' || max !== 'undefined' - ? `SizedTuple<${td.typeDeclaration},${min},${max}>` - : `${td.typeDeclaration}[]`, - typeDependencies: td.typeDependencies, - comment: comment, - } - - case 'integer': - case 'boolean': - case 'string': - case 'null': - case 'number': - return { - typeDeclaration: schema.type === 'integer' ? 'number' : schema.type, - typeDependencies: [], - comment: comment, - } - } - - return { - typeDeclaration: 'any', - typeDependencies: [], - comment: comment, - } -} diff --git a/helper/crosslab-typescript-addon/src/index.ts b/helper/crosslab-typescript-addon/src/index.ts index 73f323a3..583e14d0 100644 --- a/helper/crosslab-typescript-addon/src/index.ts +++ b/helper/crosslab-typescript-addon/src/index.ts @@ -1,4 +1,4 @@ -import { TypeScriptFilterCollection } from './filters/typescript' +import { TypeScriptFilterCollection } from './filterCollections/typescript' import { attributeEqualTo } from './tests' import { Addon } from '@cross-lab-project/openapi-codegen' import path from 'path' @@ -43,7 +43,12 @@ const CrosslabTypeScriptAddon: Addon = { name: 'service:test', filterCollections: [TypeScriptFilterCollection], globals: [], - tests: [], + tests: [ + { + name: 'attrequalto', + function: attributeEqualTo, + }, + ], templatesDir: templateDir + '/templates/service-test', }, { diff --git a/helper/crosslab-typescript-addon/templates/client-basicValidation/basicValidation.ts.njk b/helper/crosslab-typescript-addon/templates/client-basicValidation/basicValidation.ts.njk index 5693d0d5..1c927e63 100644 --- a/helper/crosslab-typescript-addon/templates/client-basicValidation/basicValidation.ts.njk +++ b/helper/crosslab-typescript-addon/templates/client-basicValidation/basicValidation.ts.njk @@ -5,4 +5,4 @@ * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, * and run openapi-codegeneration to regenerate this file. */ -{{ schemas | validation | safe }} \ No newline at end of file +{{ schemas | generateBasicValidationFunctions | safe | prettier }} \ No newline at end of file diff --git a/helper/crosslab-typescript-addon/templates/service-test/basicValidation.spec.ts.njk b/helper/crosslab-typescript-addon/templates/service-test/basicValidation.spec.ts.njk index 1f9767db..488b0c87 100644 --- a/helper/crosslab-typescript-addon/templates/service-test/basicValidation.spec.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service-test/basicValidation.spec.ts.njk @@ -40,7 +40,7 @@ export default () => describe("Basic Validation Tests", function () { }) {% set standardSchema = schema | clone -%} {% for key, value in standardSchema -%} - {%- if key | startswith("x-") -%} + {%- if key | startsWith("x-") -%} {{ standardSchema | delete(key) }} {%- endif -%} {% endfor -%} @@ -59,7 +59,7 @@ export default () => describe("Basic Validation Tests", function () { }) {% set standardSchemaWithoutUnrequired = schemaWithoutUnrequired.schema | clone -%} {% for key, value in standardSchemaWithoutUnrequired -%} - {%- if key | startswith("x-") -%} + {%- if key | startsWith("x-") -%} {{ standardSchemaWithoutUnrequired | delete(key) }} {%- endif -%} {% endfor -%} @@ -89,7 +89,7 @@ export default () => describe("Basic Validation Tests", function () { }) {% set standardInvalidSchema = invalidSchema.schema | clone -%} {% for key, value in standardInvalidSchema -%} - {%- if key | startswith("x-") -%} + {%- if key | startsWith("x-") -%} {{ standardInvalidSchema | delete(key) }} {%- endif -%} {% endfor -%} diff --git a/helper/crosslab-typescript-addon/templates/service-test/requestValidation.spec.ts.njk b/helper/crosslab-typescript-addon/templates/service-test/requestValidation.spec.ts.njk index b031ecc1..ed6a3990 100644 --- a/helper/crosslab-typescript-addon/templates/service-test/requestValidation.spec.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service-test/requestValidation.spec.ts.njk @@ -201,7 +201,7 @@ export default () => describe("Request Validation Tests", function () { const fakeBody = JSONSchemaFaker.generate(schemaBody) {%- endif %} assert(validate{{ operation.name | cap }}Output({ - {{ "status: " }}{{ response.status if not response.status | endswith("XX") else response.status[0] + "00" }}{{ "," }} + {{ "status: " }}{{ response.status if not response.status | endsWith("XX") else response.status[0] + "00" }}{{ "," }} {{- "\n\t\t\tbody: fakeBody," if response.schema }} {{- "\n\t\t\theaders: fakeHeaders," if response.headers and response.headers | length > 0 }} })) @@ -218,7 +218,7 @@ export default () => describe("Request Validation Tests", function () { const fakeBody = JSONSchemaFaker.generate(schemaBody) {%- endif %} assert(!validate{{ operation.name | cap }}Output({ - {{ "status: " }}{{ response.status if not response.status | endswith("XX") else response.status[0] + "00" }}{{ "," }} + {{ "status: " }}{{ response.status if not response.status | endsWith("XX") else response.status[0] + "00" }}{{ "," }} {{- "\n\t\t\tbody: fakeBody," if response.schema }} {{- "\n\t\t\theaders: fakeHeaders," if response.headers and response.headers | length > 0 }} })) @@ -232,7 +232,7 @@ export default () => describe("Request Validation Tests", function () { const fakeBody = JSONSchemaFaker.generate(schemaBody) {%- endif %} assert(validate{{ operation.name | cap }}Output({ - {{ "status: " }}{{ response.status if not response.status | endswith("XX") else response.status[0] + "00" }}{{ "," }} + {{ "status: " }}{{ response.status if not response.status | endsWith("XX") else response.status[0] + "00" }}{{ "," }} {{- "\n\t\t\tbody: fakeBody," if response.schema }} {{- "\n\t\t\theaders: fakeHeaders," if response.headers and response.headers | length > 0 }} })) @@ -248,7 +248,7 @@ export default () => describe("Request Validation Tests", function () { const fakeBody = JSONSchemaFaker.generate(schemaBody) {%- endif %} assert(!validate{{ operation.name | cap }}Output({ - {{ "status: " }}{{ response.status if not response.status | endswith("XX") else response.status[0] + "00" }}{{ "," }} + {{ "status: " }}{{ response.status if not response.status | endsWith("XX") else response.status[0] + "00" }}{{ "," }} {{- "\n\t\t\tbody: fakeBody," if response.schema }} {{- "\n\t\t\theaders: fakeHeaders as any," if response.headers and response.headers | length > 0 }} })) @@ -278,7 +278,7 @@ export default () => describe("Request Validation Tests", function () { const fakeBody = JSONSchemaFaker.generate(schemaBody) {%- endif %} assert(!validate{{ operation.name | cap }}Output({ - {{ "status: " }}{{ response.status if not response.status | endswith("XX") else response.status[0] + "00" }}{{ "," }} + {{ "status: " }}{{ response.status if not response.status | endsWith("XX") else response.status[0] + "00" }}{{ "," }} {{- "\n\t\t\tbody: fakeBody," if response.schema }} {{- "\n\t\t\theaders: fakeHeaders," if response.headers and response.headers | length > 0 }} })) @@ -301,7 +301,7 @@ export default () => describe("Request Validation Tests", function () { const schemaBody: Schema = {{ { "not": response.schema } | stringify(4) | indent(8) }} const fakeBody = JSONSchemaFaker.generate(schemaBody) assert(!validate{{ operation.name | cap }}Output({ - {{ "status: " }}{{ response.status if not response.status | endswith("XX") else response.status[0] + "00" }}{{ "," }} + {{ "status: " }}{{ response.status if not response.status | endsWith("XX") else response.status[0] + "00" }}{{ "," }} {{- "\n\t\t\tbody: fakeBody," if response.schema }} {{- "\n\t\t\theaders: fakeHeaders," if response.headers and response.headers | length > 0 }} })) diff --git a/helper/crosslab-typescript-addon/templates/service-test/types.spec.ts.njk b/helper/crosslab-typescript-addon/templates/service-test/types.spec.ts.njk index 876d4411..dc014a6d 100644 --- a/helper/crosslab-typescript-addon/templates/service-test/types.spec.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service-test/types.spec.ts.njk @@ -1,4 +1,4 @@ -{%- set schemas = (api | resolveSchemas) | selectattr("x-typeguard") | sortByAttribute("x-schema-type") -%} +{%- set schemas = (api | resolveSchemas) | selectattr("x-typeguard") | select("attrequalto", ["x-standalone", true]) | sortByAttribute("x-schema-type") -%} import { assert } from "console" import * as sinon from "sinon" diff --git a/helper/crosslab-typescript-addon/templates/service/basicValidation.ts.njk b/helper/crosslab-typescript-addon/templates/service/basicValidation.ts.njk index 96dffeb3..ce6a4fb8 100644 --- a/helper/crosslab-typescript-addon/templates/service/basicValidation.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service/basicValidation.ts.njk @@ -5,4 +5,4 @@ * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, * and run openapi-codegeneration to regenerate this file. */ -{{ schemas | validation | safe }} \ No newline at end of file +{{ schemas | generateBasicValidationFunctions | safe | prettier }} \ No newline at end of file diff --git a/helper/crosslab-typescript-addon/templates/service/requestValidation.ts.njk b/helper/crosslab-typescript-addon/templates/service/requestValidation.ts.njk index 0c336daa..3c91b6c1 100644 --- a/helper/crosslab-typescript-addon/templates/service/requestValidation.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service/requestValidation.ts.njk @@ -102,7 +102,7 @@ export function validate{{ operation.name | cap }}Output(response: ResponseData) if (response.status < 100 || response.status >= 600) return false {% for response in operation.responses -%} - {%- if response.status | endswith("XX") %} + {%- if response.status | endsWith("XX") %} if (response.status >= {{ (response.status | replace("X","0") | int) }} && response.status < {{ (response.status | replace("X","0") | int) + 100 }} ) { {%- else %} if (response.status === {{ response.status }}) { diff --git a/helper/crosslab-typescript-addon/templates/service/routes.ts.njk b/helper/crosslab-typescript-addon/templates/service/routes.ts.njk index 8de7ab51..9bcb476b 100644 --- a/helper/crosslab-typescript-addon/templates/service/routes.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service/routes.ts.njk @@ -77,14 +77,14 @@ export default function routes( {%- for parameter in operation.parameters -%} {%- if parameter.in == "path" -%} - {%- set pathParameters = (pathParameters.push('"' + parameter.name + '": ' + parameter.schema | typeDeclaration), pathParameters) -%} + {%- set pathParameters = (pathParameters.push('"' + parameter.name + '": string'), pathParameters) -%} {%- endif -%} {%- if parameter.in == "query" -%} - {%- set queryParameters = (queryParameters.push('"' + parameter.name + '": ' + parameter.schema | typeDeclaration), queryParameters) -%} + {%- set queryParameters = (queryParameters.push('"' + parameter.name + '": string'), queryParameters) -%} {%- endif -%} {%- endfor -%} - router.{{ operation.method }}("{{ operation.path | expressPath }}", async (req: TypedRequest< + router.{{ operation.method }}("{{ operation.path | formatExpressPath }}", async (req: TypedRequest< {{- "{ " + (pathParameters | join(", ")) + " }" if pathParameters | length > 0 else "{}" -}}, {{- operation.name + "RequestBodyType" if operation.requestBody else "{}" -}}, {{- "{ " + (queryParameters | join(", ")) + " }" if queryParameters | length > 0 else "{}" -}} @@ -97,7 +97,7 @@ export default function routes( {%- for securityMethod, scopes in securityRequirement -%} {%- set temp = (temp.push(securityMethod | formatName), temp) -%} {%- endfor -%} - {%- set userDataTypes = (userDataTypes.push("UserData<" + (temp | strings | join("|")) + ">"), userDataTypes) -%} + {%- set userDataTypes = (userDataTypes.push("UserData<" + (temp | toStrings | join("|")) + ">"), userDataTypes) -%} {%- endfor -%} const security = {{ operation.security | stringify(4) | indent(8) }} @@ -128,7 +128,7 @@ export default function routes( parameterDefinitions.push( '"' + parameter.name + '": ' + ('req.params["' + parameter.name + '"]' if parameter.in == "path") - + ('req.query["' + parameter.name + '"]' if parameter.in == "query") + + ('req.query["' + parameter.name + '"]' + (' === "true"' if parameter.schema.type == "boolean") if parameter.in == "query") + ('req.get("' + parameter.name + '")' if parameter.in == "header") + ('req.cookies["' + parameter.name + '"' if parameter.in == "cookie") ), parameterDefinitions) -%} diff --git a/helper/crosslab-typescript-addon/templates/service/signatures.ts.njk b/helper/crosslab-typescript-addon/templates/service/signatures.ts.njk index 47833be6..1d0b8cfe 100644 --- a/helper/crosslab-typescript-addon/templates/service/signatures.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service/signatures.ts.njk @@ -38,7 +38,7 @@ export type {{ operation.name }}Signature = ( {%- for securityMethod, scopes in securityRequirement -%} {%- set temp = (temp.push(securityMethod | formatName), temp) -%} {%- endfor -%} - {%- set userDataTypes = (userDataTypes.push("UserData<" + (temp | strings | join("|")) + ">"), userDataTypes) -%} + {%- set userDataTypes = (userDataTypes.push("UserData<" + (temp | toStrings | join("|")) + ">"), userDataTypes) -%} {%- endfor -%} {%- else -%} {%- set userDataTypes = ["undefined"] -%} @@ -119,7 +119,7 @@ export type {{ operation.name }}ErrorResponseType = {{ error_responses | join(" * Typing for a response with status {{ response.status }} to a {{ operation.method | upper }} request on {{ operation.path }} */ export interface {{ operation.name }}{{ response.status }}ResponseType extends {{ "SuccessResponse" if response.status | int < 400 else "ErrorResponse" }} { - status: {{ ("NumericRange<" + (response.status | replace("XX", "00")) + "," + (response.status | replace("XX", "00") | int + 100) + ">") if (response.status | endswith("XX")) else response.status }} + status: {{ ("NumericRange<" + (response.status | replace("XX", "00")) + "," + (response.status | replace("XX", "00") | int + 100) + ">") if (response.status | endsWith("XX")) else response.status }} headers{{ "?" if not response.headers }}: { {% for header in response.headers -%} "{{ header.name }}"{{ "?" if not header.required}}: {{ header.schema | typeDeclaration(schemas, { "schemaType": "response" }) | indent(8) if header.schema else "undefined" }}, From 55ff89a4e24bf45f660d5e36a0f39bb30e195418 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 27 Mar 2023 11:59:47 +0200 Subject: [PATCH 13/33] Update API and add empty test functions --- services/device/.gitignore | 5 +- services/device/api/content/device_init.yml | 2 +- .../api/content/device_instantiated.yml | 5 +- .../device/api/schemas/devices/device.yml | 5 +- .../api/schemas/devices/device_group.yml | 2 +- .../api/schemas/devices/device_overview.yml | 1 + .../init/device_cloud_instantiable_init.yml | 20 - .../devices/init/device_concrete_init.yml | 20 - .../init/device_edge_instantiable_init.yml | 20 - .../devices/init/device_group_init.yml | 16 - .../api/schemas/devices/init/device_init.yml | 7 - .../devices/init/device_overview_init.yml | 24 - .../configured_device_reference.yml | 2 +- .../{ => references}/device_reference.yml | 0 .../device_cloud_instantiable_update.yml | 4 +- .../devices/update/device_concrete_update.yml | 4 +- .../device_edge_instantiable_update.yml | 4 +- .../devices/update/device_group_update.yml | 7 +- .../devices/update/device_overview_update.yml | 12 +- .../schemas/devices/update/device_update.yml | 2 +- .../peerconnections/peerconnection.yml | 2 +- .../peerconnection_overview.yml | 2 +- services/device/dist/openapi.json | 271 +-- services/device/package-lock.json | 1994 ++++++++++++++++- services/device/package.json | 28 +- services/device/src/database/model.ts | 2 +- .../src/database/repositories/device.ts | 25 +- .../repositories/device/concreteDevice.ts | 11 +- .../repositories/device/deviceGroup.ts | 3 +- .../device/instantiableBrowserDevice.ts | 3 +- .../device/instantiableCloudDevice.ts | 3 +- .../src/operations/devices/device/patch.ts | 16 +- .../src/operations/devices/device/post.ts | 12 + .../device/src/operations/devices/post.ts | 4 + .../concreteDevices/concrete_device.spec.ts | 4 +- .../devices/deviceGroups/device_group.spec.ts | 8 +- .../instantiable_browser_device.spec.ts | 3 +- .../instantiable_cloud_device.spec.ts | 3 +- .../example_peerconnection.spec.ts | 10 +- .../device/test/database/dataSource.spec.ts | 0 services/device/test/database/model.spec.ts | 0 .../test/database/repositories/device.spec.ts | 26 +- .../device/concreteDevice.spec.ts | 40 +- .../repositories/device/deviceGroup.spec.ts | 28 +- .../device/deviceOverview.spec.ts | 21 +- .../device/instantiableBrowserDevice.spec.ts | 23 +- .../device/instantiableCloudDevice.spec.ts | 23 +- .../test/database/repositories/index.spec.ts | 8 + .../repositories/peerconnection.spec.ts | 57 +- .../device/test/methods/availability.spec.ts | 12 + .../device/test/methods/callbacks.spec.ts | 8 + .../device/test/methods/signaling.spec.ts | 6 + .../device/test/methods/urlFromId.spec.ts | 6 + .../devices/device/availability/index.spec.ts | 3 + .../devices/device/availability/post.spec.ts | 8 + .../operations/devices/device/delete.spec.ts | 8 + .../operations/devices/device/get.spec.ts | 8 + .../operations/devices/device/index.spec.ts | 6 + .../operations/devices/device/patch.spec.ts | 8 + .../operations/devices/device/post.spec.ts | 8 + .../devices/device/signaling/index.spec.ts | 3 + .../devices/device/signaling/post.spec.ts | 8 + .../devices/device/websocket/index.spec.ts | 3 + .../devices/device/websocket/post.spec.ts | 8 + .../test/operations/devices/get.spec.ts | 32 + .../test/operations/devices/index.spec.ts | 4 + .../test/operations/devices/post.spec.ts | 8 + services/device/test/operations/index.spec.ts | 36 + .../operations/peerconnections/get.spec.ts | 32 + .../operations/peerconnections/index.spec.ts | 4 + .../peerconnection/delete.spec.ts | 8 + .../device_status/index.spec.ts | 3 + .../device_status/patch.spec.ts | 11 + .../peerconnection/get.spec.ts | 8 + .../peerconnection/index.spec.ts | 4 + .../operations/peerconnections/post.spec.ts | 8 + 76 files changed, 2562 insertions(+), 491 deletions(-) delete mode 100644 services/device/api/schemas/devices/init/device_cloud_instantiable_init.yml delete mode 100644 services/device/api/schemas/devices/init/device_concrete_init.yml delete mode 100644 services/device/api/schemas/devices/init/device_edge_instantiable_init.yml delete mode 100644 services/device/api/schemas/devices/init/device_group_init.yml delete mode 100644 services/device/api/schemas/devices/init/device_init.yml delete mode 100644 services/device/api/schemas/devices/init/device_overview_init.yml rename services/device/api/schemas/devices/{ => references}/configured_device_reference.yml (86%) rename services/device/api/schemas/devices/{ => references}/device_reference.yml (100%) delete mode 100644 services/device/test/database/dataSource.spec.ts delete mode 100644 services/device/test/database/model.spec.ts create mode 100644 services/device/test/operations/peerconnections/peerconnection/device_status/index.spec.ts create mode 100644 services/device/test/operations/peerconnections/peerconnection/device_status/patch.spec.ts diff --git a/services/device/.gitignore b/services/device/.gitignore index 6e936f86..5c8a398b 100644 --- a/services/device/.gitignore +++ b/services/device/.gitignore @@ -1,10 +1,11 @@ dist/* !dist/openapi.json -src/generated +generated node_modules .npmrc *.db package.resolved.json .packages app -.nyc_output \ No newline at end of file +.nyc_output +coverage \ No newline at end of file diff --git a/services/device/api/content/device_init.yml b/services/device/api/content/device_init.yml index 103a5eca..1fb04f58 100644 --- a/services/device/api/content/device_init.yml +++ b/services/device/api/content/device_init.yml @@ -1,6 +1,6 @@ # yaml-language-server: $schema=https://cross-lab-project.github.io/crosslab/meta-schemas/openapi-content.json schema: - $ref: ../schemas/devices/init/device_init.yml + $ref: ../schemas/devices/device.yml examples: microcontroller: value: diff --git a/services/device/api/content/device_instantiated.yml b/services/device/api/content/device_instantiated.yml index 6e52259a..3e8c7334 100644 --- a/services/device/api/content/device_instantiated.yml +++ b/services/device/api/content/device_instantiated.yml @@ -5,4 +5,7 @@ schema: instance: $ref: '../schemas/devices/device_concrete.yml' deviceToken: - type: string \ No newline at end of file + type: string + required: + - instance + - deviceToken \ No newline at end of file diff --git a/services/device/api/schemas/devices/device.yml b/services/device/api/schemas/devices/device.yml index da53863b..47714468 100644 --- a/services/device/api/schemas/devices/device.yml +++ b/services/device/api/schemas/devices/device.yml @@ -1,7 +1,8 @@ # yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema title: Device -oneOf: +anyOf: - $ref: ./device_cloud_instantiable.yml - $ref: ./device_concrete.yml - $ref: ./device_edge_instantiable.yml - - $ref: ./device_group.yml \ No newline at end of file + - $ref: ./device_group.yml +x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/devices/device_group.yml b/services/device/api/schemas/devices/device_group.yml index de61e320..1c362016 100644 --- a/services/device/api/schemas/devices/device_group.yml +++ b/services/device/api/schemas/devices/device_group.yml @@ -9,5 +9,5 @@ allOf: devices: type: array items: - $ref: ./device_reference.yml + $ref: ./references/device_reference.yml x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/devices/device_overview.yml b/services/device/api/schemas/devices/device_overview.yml index 2f09ca06..64cac90a 100644 --- a/services/device/api/schemas/devices/device_overview.yml +++ b/services/device/api/schemas/devices/device_overview.yml @@ -29,4 +29,5 @@ required: - url - type - name + - owner x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/devices/init/device_cloud_instantiable_init.yml b/services/device/api/schemas/devices/init/device_cloud_instantiable_init.yml deleted file mode 100644 index f3470b22..00000000 --- a/services/device/api/schemas/devices/init/device_cloud_instantiable_init.yml +++ /dev/null @@ -1,20 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -title: Instantiable Cloud Device Init -allOf: - - $ref: ./device_overview_init.yml - - type: object - properties: - type: - const: cloud instantiable - writeOnly: true - instantiateUrl: - type: string - format: uri - writeOnly: true - services: - type: array - items: - $ref: ../services/service_description.yml - writeOnly: true - required: - - type diff --git a/services/device/api/schemas/devices/init/device_concrete_init.yml b/services/device/api/schemas/devices/init/device_concrete_init.yml deleted file mode 100644 index 6129952b..00000000 --- a/services/device/api/schemas/devices/init/device_concrete_init.yml +++ /dev/null @@ -1,20 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -title: Concrete Device Init -allOf: - - $ref: ./device_overview_init.yml - - type: object - properties: - type: - const: device - writeOnly: true - experiment: - type: string - format: uri - writeOnly: true - services: - type: array - items: - $ref: ../services/service_description.yml - writeOnly: true - required: - - type diff --git a/services/device/api/schemas/devices/init/device_edge_instantiable_init.yml b/services/device/api/schemas/devices/init/device_edge_instantiable_init.yml deleted file mode 100644 index 9805a1cc..00000000 --- a/services/device/api/schemas/devices/init/device_edge_instantiable_init.yml +++ /dev/null @@ -1,20 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -title: Instantiable Browser Device Init -allOf: - - $ref: ./device_overview_init.yml - - type: object - properties: - type: - const: edge instantiable - writeOnly: true - codeUrl: - type: string - format: uri - writeOnly: true - services: - type: array - items: - $ref: ../services/service_description.yml - writeOnly: true - required: - - type \ No newline at end of file diff --git a/services/device/api/schemas/devices/init/device_group_init.yml b/services/device/api/schemas/devices/init/device_group_init.yml deleted file mode 100644 index c4fe9d7e..00000000 --- a/services/device/api/schemas/devices/init/device_group_init.yml +++ /dev/null @@ -1,16 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -title: Device Group Init -allOf: - - $ref: ./device_overview_init.yml - - type: object - properties: - type: - const: group - writeOnly: true - devices: - type: array - items: - $ref: ../device_reference.yml - writeOnly: true - required: - - type \ No newline at end of file diff --git a/services/device/api/schemas/devices/init/device_init.yml b/services/device/api/schemas/devices/init/device_init.yml deleted file mode 100644 index 20c72304..00000000 --- a/services/device/api/schemas/devices/init/device_init.yml +++ /dev/null @@ -1,7 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -title: Device Init -oneOf: - - $ref: ./device_cloud_instantiable_init.yml - - $ref: ./device_concrete_init.yml - - $ref: ./device_edge_instantiable_init.yml - - $ref: ./device_group_init.yml \ No newline at end of file diff --git a/services/device/api/schemas/devices/init/device_overview_init.yml b/services/device/api/schemas/devices/init/device_overview_init.yml deleted file mode 100644 index fc40260f..00000000 --- a/services/device/api/schemas/devices/init/device_overview_init.yml +++ /dev/null @@ -1,24 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -title: Device Overview Init -type: object -properties: - name: - type: string - description: Name of the device - writeOnly: true - description: - type: string - description: Extended description of the device, features, etc. - writeOnly: true - type: - type: string - description: Type of the device - enum: - - device - - group - - edge instantiable - - cloud instantiable - writeOnly: true -required: - - type - - name \ No newline at end of file diff --git a/services/device/api/schemas/devices/configured_device_reference.yml b/services/device/api/schemas/devices/references/configured_device_reference.yml similarity index 86% rename from services/device/api/schemas/devices/configured_device_reference.yml rename to services/device/api/schemas/devices/references/configured_device_reference.yml index 1019eb47..4447799e 100644 --- a/services/device/api/schemas/devices/configured_device_reference.yml +++ b/services/device/api/schemas/devices/references/configured_device_reference.yml @@ -12,6 +12,6 @@ properties: services: type: array items: - $ref: './services/service_config.yml' + $ref: '../services/service_config.yml' required: - url \ No newline at end of file diff --git a/services/device/api/schemas/devices/device_reference.yml b/services/device/api/schemas/devices/references/device_reference.yml similarity index 100% rename from services/device/api/schemas/devices/device_reference.yml rename to services/device/api/schemas/devices/references/device_reference.yml diff --git a/services/device/api/schemas/devices/update/device_cloud_instantiable_update.yml b/services/device/api/schemas/devices/update/device_cloud_instantiable_update.yml index 097f8204..73b8d014 100644 --- a/services/device/api/schemas/devices/update/device_cloud_instantiable_update.yml +++ b/services/device/api/schemas/devices/update/device_cloud_instantiable_update.yml @@ -4,12 +4,12 @@ allOf: - $ref: ./device_overview_update.yml - type: object properties: + type: + const: cloud instantiable instantiateUrl: type: string format: uri - writeOnly: true services: type: array items: $ref: ../services/service_description.yml - writeOnly: true diff --git a/services/device/api/schemas/devices/update/device_concrete_update.yml b/services/device/api/schemas/devices/update/device_concrete_update.yml index 3ecd1d6a..2d926752 100644 --- a/services/device/api/schemas/devices/update/device_concrete_update.yml +++ b/services/device/api/schemas/devices/update/device_concrete_update.yml @@ -4,12 +4,12 @@ allOf: - $ref: ./device_overview_update.yml - type: object properties: + type: + const: device experiment: type: string format: uri - writeOnly: true services: type: array items: $ref: ../services/service_description.yml - writeOnly: true diff --git a/services/device/api/schemas/devices/update/device_edge_instantiable_update.yml b/services/device/api/schemas/devices/update/device_edge_instantiable_update.yml index 6c5b8f2a..7b35143b 100644 --- a/services/device/api/schemas/devices/update/device_edge_instantiable_update.yml +++ b/services/device/api/schemas/devices/update/device_edge_instantiable_update.yml @@ -4,12 +4,12 @@ allOf: - $ref: ./device_overview_update.yml - type: object properties: + type: + const: edge instantiable codeUrl: type: string format: uri - writeOnly: true services: type: array items: $ref: ../services/service_description.yml - writeOnly: true diff --git a/services/device/api/schemas/devices/update/device_group_update.yml b/services/device/api/schemas/devices/update/device_group_update.yml index 8e92509b..0819da04 100644 --- a/services/device/api/schemas/devices/update/device_group_update.yml +++ b/services/device/api/schemas/devices/update/device_group_update.yml @@ -1,11 +1,12 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema + # yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema title: Device Group Update allOf: - $ref: ./device_overview_update.yml - type: object properties: + type: + const: group devices: type: array items: - $ref: ../device_reference.yml - writeOnly: true \ No newline at end of file + $ref: ../references/device_reference.yml \ No newline at end of file diff --git a/services/device/api/schemas/devices/update/device_overview_update.yml b/services/device/api/schemas/devices/update/device_overview_update.yml index 9493832d..2c426aee 100644 --- a/services/device/api/schemas/devices/update/device_overview_update.yml +++ b/services/device/api/schemas/devices/update/device_overview_update.yml @@ -5,8 +5,16 @@ properties: name: type: string description: Name of the device - writeOnly: true description: type: string description: Extended description of the device, features, etc. - writeOnly: true \ No newline at end of file + type: + type: string + description: Type of the device + enum: + - device + - group + - edge instantiable + - cloud instantiable +required: + - type \ No newline at end of file diff --git a/services/device/api/schemas/devices/update/device_update.yml b/services/device/api/schemas/devices/update/device_update.yml index 417d14c1..95cd491a 100644 --- a/services/device/api/schemas/devices/update/device_update.yml +++ b/services/device/api/schemas/devices/update/device_update.yml @@ -1,6 +1,6 @@ # yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema title: Device Update -oneOf: +anyOf: - $ref: ./device_cloud_instantiable_update.yml - $ref: ./device_concrete_update.yml - $ref: ./device_edge_instantiable_update.yml diff --git a/services/device/api/schemas/peerconnections/peerconnection.yml b/services/device/api/schemas/peerconnections/peerconnection.yml index dc95cda4..5e090dd6 100644 --- a/services/device/api/schemas/peerconnections/peerconnection.yml +++ b/services/device/api/schemas/peerconnections/peerconnection.yml @@ -9,7 +9,7 @@ allOf: minItems: 2 maxItems: 2 items: - $ref: "../devices/configured_device_reference.yml" + $ref: "../devices/references/configured_device_reference.yml" required: - devices x-typeguard: true \ No newline at end of file diff --git a/services/device/api/schemas/peerconnections/peerconnection_overview.yml b/services/device/api/schemas/peerconnections/peerconnection_overview.yml index f38d1400..80b77c5d 100644 --- a/services/device/api/schemas/peerconnections/peerconnection_overview.yml +++ b/services/device/api/schemas/peerconnections/peerconnection_overview.yml @@ -9,6 +9,6 @@ allOf: minItems: 2 maxItems: 2 items: - $ref: "../devices/device_reference.yml" + $ref: "../devices/references/device_reference.yml" required: - devices \ No newline at end of file diff --git a/services/device/dist/openapi.json b/services/device/dist/openapi.json index d8f34d39..983c5f2f 100644 --- a/services/device/dist/openapi.json +++ b/services/device/dist/openapi.json @@ -107,41 +107,11 @@ "required": [ "url", "type", - "name" + "name", + "owner" ], "x-typeguard": true }, - "device_overview_init": { - "title": "Device Overview Init", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the device", - "writeOnly": true - }, - "description": { - "type": "string", - "description": "Extended description of the device, features, etc.", - "writeOnly": true - }, - "type": { - "type": "string", - "description": "Type of the device", - "enum": [ - "device", - "group", - "edge instantiable", - "cloud instantiable" - ], - "writeOnly": true - } - }, - "required": [ - "type", - "name" - ] - }, "service_description": { "title": "Service Description", "type": "object", @@ -164,160 +134,6 @@ }, "additionalProperties": true }, - "device_cloud_instantiable_init": { - "title": "Instantiable Cloud Device Init", - "allOf": [ - { - "$ref": "#/components/schemas/device_overview_init" - }, - { - "type": "object", - "properties": { - "type": { - "const": "cloud instantiable", - "writeOnly": true - }, - "instantiateUrl": { - "type": "string", - "format": "uri", - "writeOnly": true - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true - } - }, - "required": [ - "type" - ] - } - ] - }, - "device_concrete_init": { - "title": "Concrete Device Init", - "allOf": [ - { - "$ref": "#/components/schemas/device_overview_init" - }, - { - "type": "object", - "properties": { - "type": { - "const": "device", - "writeOnly": true - }, - "experiment": { - "type": "string", - "format": "uri", - "writeOnly": true - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true - } - }, - "required": [ - "type" - ] - } - ] - }, - "device_edge_instantiable_init": { - "title": "Instantiable Browser Device Init", - "allOf": [ - { - "$ref": "#/components/schemas/device_overview_init" - }, - { - "type": "object", - "properties": { - "type": { - "const": "edge instantiable", - "writeOnly": true - }, - "codeUrl": { - "type": "string", - "format": "uri", - "writeOnly": true - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true - } - }, - "required": [ - "type" - ] - } - ] - }, - "device_reference": { - "title": "Device Reference", - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "URL of the device", - "format": "uri" - } - }, - "required": [ - "url" - ] - }, - "device_group_init": { - "title": "Device Group Init", - "allOf": [ - { - "$ref": "#/components/schemas/device_overview_init" - }, - { - "type": "object", - "properties": { - "type": { - "const": "group", - "writeOnly": true - }, - "devices": { - "type": "array", - "items": { - "$ref": "#/components/schemas/device_reference" - }, - "writeOnly": true - } - }, - "required": [ - "type" - ] - } - ] - }, - "device_init": { - "title": "Device Init", - "oneOf": [ - { - "$ref": "#/components/schemas/device_cloud_instantiable_init" - }, - { - "$ref": "#/components/schemas/device_concrete_init" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable_init" - }, - { - "$ref": "#/components/schemas/device_group_init" - } - ] - }, "device_cloud_instantiable": { "title": "Instantiable Cloud Device", "allOf": [ @@ -430,6 +246,20 @@ ], "x-typeguard": true }, + "device_reference": { + "title": "Device Reference", + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL of the device", + "format": "uri" + } + }, + "required": [ + "url" + ] + }, "device_group": { "title": "Device Group", "allOf": [ @@ -455,7 +285,7 @@ }, "device": { "title": "Device", - "oneOf": [ + "anyOf": [ { "$ref": "#/components/schemas/device_cloud_instantiable" }, @@ -468,7 +298,8 @@ { "$ref": "#/components/schemas/device_group" } - ] + ], + "x-typeguard": true }, "device_overview_update": { "title": "Device Overview Update", @@ -476,15 +307,26 @@ "properties": { "name": { "type": "string", - "description": "Name of the device", - "writeOnly": true + "description": "Name of the device" }, "description": { "type": "string", - "description": "Extended description of the device, features, etc.", - "writeOnly": true + "description": "Extended description of the device, features, etc." + }, + "type": { + "type": "string", + "description": "Type of the device", + "enum": [ + "device", + "group", + "edge instantiable", + "cloud instantiable" + ] } - } + }, + "required": [ + "type" + ] }, "device_cloud_instantiable_update": { "title": "Instantiable Cloud Device Update", @@ -495,17 +337,18 @@ { "type": "object", "properties": { + "type": { + "const": "cloud instantiable" + }, "instantiateUrl": { "type": "string", - "format": "uri", - "writeOnly": true + "format": "uri" }, "services": { "type": "array", "items": { "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true + } } } } @@ -520,17 +363,18 @@ { "type": "object", "properties": { + "type": { + "const": "device" + }, "experiment": { "type": "string", - "format": "uri", - "writeOnly": true + "format": "uri" }, "services": { "type": "array", "items": { "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true + } } } } @@ -545,17 +389,18 @@ { "type": "object", "properties": { + "type": { + "const": "edge instantiable" + }, "codeUrl": { "type": "string", - "format": "uri", - "writeOnly": true + "format": "uri" }, "services": { "type": "array", "items": { "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true + } } } } @@ -570,12 +415,14 @@ { "type": "object", "properties": { + "type": { + "const": "group" + }, "devices": { "type": "array", "items": { "$ref": "#/components/schemas/device_reference" - }, - "writeOnly": true + } } } } @@ -583,7 +430,7 @@ }, "device_update": { "title": "Device Update", - "oneOf": [ + "anyOf": [ { "$ref": "#/components/schemas/device_cloud_instantiable_update" }, @@ -1108,7 +955,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/device_init" + "$ref": "#/components/schemas/device" }, "examples": { "microcontroller": { @@ -1977,7 +1824,11 @@ "deviceToken": { "type": "string" } - } + }, + "required": [ + "instance", + "deviceToken" + ] } } } diff --git a/services/device/package-lock.json b/services/device/package-lock.json index e4268635..7bf03f01 100644 --- a/services/device/package-lock.json +++ b/services/device/package-lock.json @@ -33,15 +33,26 @@ "@types/mocha": "^10.0.1", "@types/node": "^18.0.3", "@types/node-fetch": "^2.6.1", + "@types/rewire": "^2.5.28", + "@types/seedrandom": "^3.0.5", + "@types/sinon": "^10.0.13", + "@types/supertest": "^2.0.12", "@types/ws": "^8.5.3", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "env-cmd": "^10.1.0", "eslint": "^8.34.0", + "json-schema-faker": "^0.5.0-rcv.46", "mocha": "^10.2.0", "nodemon": "^2.0.19", + "npm-run-all": "^4.1.5", "nyc": "^15.1.0", "prettier": "^2.7.1", + "randexp": "^0.5.3", + "rewire": "^6.0.0", + "seedrandom": "^3.0.5", + "sinon": "^15.0.2", + "supertest": "^6.3.3", "ts-mocha": "^10.0.0", "ts-node": "^10.9.1", "typescript": "^4.7.4" @@ -1253,6 +1264,59 @@ "node": ">=10" } }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0" + } + }, + "node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", + "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, "node_modules/@sqltools/formatter": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", @@ -1329,6 +1393,12 @@ "@types/node": "*" } }, + "node_modules/@types/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, "node_modules/@types/express": { "version": "4.17.17", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", @@ -1417,6 +1487,18 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "node_modules/@types/rewire": { + "version": "2.5.28", + "resolved": "https://registry.npmjs.org/@types/rewire/-/rewire-2.5.28.tgz", + "integrity": "sha512-uD0j/AQOa5le7afuK+u+woi8jNKF1vf3DN0H7LCJhft/lNNibUr7VcAesdgtWfEKveZol3ZG1CJqwx2Bhrnl8w==", + "dev": true + }, + "node_modules/@types/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-kopEpYpFQvQdYsZkZVwht/0THHmTFFYXDaqV/lM45eweJ8kcGVDgZHs0RVTolSq55UPZNmjhKc9r7UvLu/mQQg==", + "dev": true + }, "node_modules/@types/semver": { "version": "7.3.13", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", @@ -1433,6 +1515,40 @@ "@types/node": "*" } }, + "node_modules/@types/sinon": { + "version": "10.0.13", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", + "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, + "node_modules/@types/superagent": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.16.tgz", + "integrity": "sha512-tLfnlJf6A5mB6ddqF159GqcDizfzbMUB1/DeT59/wBNqzRTNNKsaw79A/1TZ84X+f/EwWH8FeuSkjlCLyqS/zQ==", + "dev": true, + "dependencies": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "node_modules/@types/supertest": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.12.tgz", + "integrity": "sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ==", + "dev": true, + "dependencies": { + "@types/superagent": "*" + } + }, "node_modules/@types/ws": { "version": "8.5.4", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", @@ -2058,6 +2174,28 @@ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "devOptional": true }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -2087,12 +2225,33 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2660,6 +2819,12 @@ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2708,6 +2873,12 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -2794,6 +2965,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2833,6 +3020,29 @@ "node": ">=8" } }, + "node_modules/deterministic-json-schema-faker": { + "version": "0.5.0-rcv.46", + "resolved": "https://registry.npmjs.org/deterministic-json-schema-faker/-/deterministic-json-schema-faker-0.5.0-rcv.46.tgz", + "integrity": "sha512-pp7iiuue97ysVTMLXyLofpDembEepoGbdv79ie2Mdhqj4dtVQFpI9c6ecxjUiDFDBxScqWpPvVpWX88PxMPZGA==", + "dev": true, + "dependencies": { + "json-schema-ref-parser": "^6.1.0", + "jsonpath-plus": "^5.1.0" + }, + "bin": { + "jsf": "bin/gen.cjs" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -2874,6 +3084,24 @@ "node": ">=12" } }, + "node_modules/drange": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", + "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.2" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2919,6 +3147,18 @@ "node": ">=0.10.0" } }, + "node_modules/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, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/env-cmd": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz", @@ -2959,6 +3199,94 @@ "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "optional": true }, + "node_modules/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, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es5-ext": { "version": "0.10.62", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", @@ -3490,6 +3818,12 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -3614,6 +3948,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -3641,6 +3984,27 @@ "node": ">= 6" } }, + "node_modules/format-util": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz", + "integrity": "sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==", + "dev": true + }, + "node_modules/formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "dev": true, + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3698,6 +4062,39 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", @@ -3768,6 +4165,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -3808,6 +4221,21 @@ "node": ">=4" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -3828,6 +4256,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -3851,6 +4291,15 @@ "node": ">= 0.4.0" } }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -3860,6 +4309,30 @@ "node": ">=4" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -3871,13 +4344,28 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" - }, - "node_modules/hasha": { - "version": "5.2.2", + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/hasha": { + "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", "dev": true, @@ -3922,6 +4410,15 @@ "he": "bin/he" } }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -3930,6 +4427,12 @@ "node": "*" } }, + "node_modules/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 + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -4091,6 +4594,20 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -4105,6 +4622,38 @@ "node": ">= 0.10" } }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4117,6 +4666,61 @@ "node": ">=8" } }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4152,6 +4756,18 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "optional": true }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4161,6 +4777,21 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -4197,6 +4828,34 @@ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", "dev": true }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -4206,6 +4865,55 @@ "node": ">=0.10.0" } }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -4230,6 +4938,18 @@ "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", "dev": true }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -4466,6 +5186,109 @@ "node": ">=4" } }, + "node_modules/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 + }, + "node_modules/json-schema-faker": { + "version": "0.5.0-rcv.46", + "resolved": "https://registry.npmjs.org/json-schema-faker/-/json-schema-faker-0.5.0-rcv.46.tgz", + "integrity": "sha512-Q+sGrxptZfezwm7M9W9VmHT9E8s5fWPCaRC4J2zUjb3CmDsxokiCBdHdS/psu91Tafc/ITv+GtIztGzUVT2zIg==", + "dev": true, + "dependencies": { + "json-schema-ref-parser": "^6.1.0", + "jsonpath-plus": "^5.1.0" + }, + "bin": { + "jsf": "bin/gen.cjs" + } + }, + "node_modules/json-schema-ref-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz", + "integrity": "sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw==", + "deprecated": "Please switch to @apidevtools/json-schema-ref-parser", + "dev": true, + "dependencies": { + "call-me-maybe": "^1.0.1", + "js-yaml": "^3.12.1", + "ono": "^4.0.11" + } + }, + "node_modules/json-schema-to-typescript": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-10.1.5.tgz", + "integrity": "sha512-X8bNNksfCQo6LhEuqNxmZr4eZpPjXZajmimciuk8eWXzZlif9Brq7WuMGD/SOhBKcRKP2SGVDNZbC28WQqx9Rg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.6", + "@types/lodash": "^4.14.168", + "@types/prettier": "^2.1.5", + "cli-color": "^2.0.0", + "get-stdin": "^8.0.0", + "glob": "^7.1.6", + "glob-promise": "^3.4.0", + "is-glob": "^4.0.1", + "json-schema-ref-parser": "^9.0.6", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.20", + "minimist": "^1.2.5", + "mkdirp": "^1.0.4", + "mz": "^2.7.0", + "prettier": "^2.2.0" + }, + "bin": { + "json2ts": "dist/src/cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/json-schema-to-typescript/node_modules/@apidevtools/json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", + "dev": true, + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, + "node_modules/json-schema-to-typescript/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/json-schema-to-typescript/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-to-typescript/node_modules/json-schema-ref-parser": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q==", + "deprecated": "Please switch to @apidevtools/json-schema-ref-parser", + "dev": true, + "dependencies": { + "@apidevtools/json-schema-ref-parser": "9.0.9" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -4498,6 +5321,12 @@ "node": ">=10.0.0" } }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -4520,6 +5349,39 @@ "node": ">= 0.8.0" } }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4547,12 +5409,24 @@ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, "node_modules/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 }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -4731,10 +5605,35 @@ "node": ">= 0.6" } }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "node_modules/merge2": { "version": "1.4.1", @@ -5195,6 +6094,55 @@ "node": ">= 0.6" } }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/nise": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", + "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/nise/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/nise/node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, "node_modules/node-addon-api": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", @@ -5415,6 +6363,27 @@ "node": ">=6" } }, + "node_modules/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, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -5424,6 +6393,98 @@ "node": ">=0.10.0" } }, + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/npm-run-all/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-run-all/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", @@ -5716,6 +6777,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -5839,6 +6927,19 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/parse5": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", @@ -5923,6 +7024,18 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -6080,6 +7193,15 @@ "node": ">=8" } }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -6237,6 +7359,19 @@ "quote-stream": "bin/cmd.js" } }, + "node_modules/randexp": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz", + "integrity": "sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==", + "dev": true, + "dependencies": { + "drange": "^1.0.2", + "ret": "^0.2.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -6268,6 +7403,41 @@ "node": ">= 0.8" } }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/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, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -6304,6 +7474,23 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -6376,6 +7563,15 @@ "node": ">=4" } }, + "node_modules/ret": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", + "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", @@ -6395,6 +7591,356 @@ "node": ">=0.10.0" } }, + "node_modules/rewire": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rewire/-/rewire-6.0.0.tgz", + "integrity": "sha512-7sZdz5dptqBCapJYocw9EcppLU62KMEqDLIILJnNET2iqzXHaQfaVP5SOJ06XvjX+dNIDJbzjw0ZWzrgDhtjYg==", + "dev": true, + "dependencies": { + "eslint": "^7.32.0" + } + }, + "node_modules/rewire/node_modules/@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, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/rewire/node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/rewire/node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/rewire/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/rewire/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/rewire/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/rewire/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/rewire/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/rewire/node_modules/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==", + "dev": true + }, + "node_modules/rewire/node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rewire/node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/rewire/node_modules/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, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/rewire/node_modules/eslint-utils/node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/rewire/node_modules/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, + "engines": { + "node": ">=10" + } + }, + "node_modules/rewire/node_modules/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, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/rewire/node_modules/espree/node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/rewire/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/rewire/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rewire/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/rewire/node_modules/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, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rewire/node_modules/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 + }, + "node_modules/rewire/node_modules/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/rewire/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/rewire/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rewire/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -6451,6 +7997,20 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -6594,6 +8154,15 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", + "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -6633,6 +8202,54 @@ "semver": "bin/semver.js" } }, + "node_modules/sinon": { + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.2.tgz", + "integrity": "sha512-PCVP63XZkg0/LOqQH5rEU4LILuvTFMb5tNxTHfs6VUMNnZz2XrnGSTZbAGITjzwQWbl/Bl/8hi4G3zZWjyBwHg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/samsam": "^7.0.1", + "diff": "^5.1.0", + "nise": "^5.1.4", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/sinon/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/sinon/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6642,6 +8259,56 @@ "node": ">=8" } }, + "node_modules/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, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/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==", + "dev": true + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -6743,6 +8410,38 @@ "node": ">=8" } }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/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 + }, + "node_modules/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, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -6825,6 +8524,68 @@ "node": ">=8" } }, + "node_modules/string.prototype.padend": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz", + "integrity": "sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6857,6 +8618,99 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/superagent": { + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz", + "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==", + "dev": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/superagent/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/superagent/node_modules/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/superagent/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/superagent/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/supertest": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", + "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", + "dev": true, + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.0.5" + }, + "engines": { + "node": ">=6.4.0" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -6869,6 +8723,34 @@ "node": ">=4" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/tar": { "version": "6.1.13", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", @@ -7183,6 +9065,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -7207,6 +9098,20 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -7478,6 +9383,21 @@ "node": ">=4.2.0" } }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -7565,12 +9485,28 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/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 + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "devOptional": true }, + "node_modules/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, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -7608,12 +9544,48 @@ "node": ">= 8" } }, + "node_modules/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==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", "dev": true }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", diff --git a/services/device/package.json b/services/device/package.json index ba98ad82..f31ccdfd 100644 --- a/services/device/package.json +++ b/services/device/package.json @@ -13,14 +13,23 @@ "openapi-bundle": "npx --yes @redocly/cli bundle ./api/openapi.yml --output dist/openapi.json", "watch-openapi": "npx --yes chokidar-cli 'api/**/*.yml' -c 'npm run openapi-bundle'", "watch-rapidoc": "npx --yes browser-sync start --server --startPath 'api/rapidoc.html' --files 'dist/openapi.json'", - "build-generate-code": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service -o src/generated", - "build-compile": "tsc --project tsconfig.build.json", - "build": "npm run build-generate-code && npm run build-compile", + "build:generate:code": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service -o src/generated", + "build:generate:test": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service:test -o test/generated", + "build:generate": "npm-run-all build:generate:*", + "build:compile": "tsc --project tsconfig.build.json", + "build": "npm-run-all build:*", "start": "node app/index.js", "dev": "env-cmd -e development npx nodemon src/index.ts", "format": "npx prettier src --write", "lint": "eslint .", - "test:database": "nyc --temp-dir .nyc_output/database --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/database/index.spec.ts" + "test:database": "nyc --temp-dir .nyc_output/database --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/database/index.spec.ts", + "test:generated": "nyc --temp-dir .nyc_output/generated --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/generated/index.spec.ts", + "test:operations": "nyc --temp-dir .nyc_output/operations --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/operations/index.spec.ts", + "test": "rm -rf coverage && rm -rf .nyc_output && npm-run-all -c test:*", + "cov:database": "nyc merge .nyc_output/database .nyc_output/database.json", + "cov:generated": "nyc merge .nyc_output/generated .nyc_output/generated.json", + "cov:operations": "nyc merge .nyc_output/operations .nyc_output/operations.json", + "cov": "npm-run-all cov:* && nyc report --reporter=text --reporter=html" }, "author": "Johannes Nau", "license": "UNLICENSED", @@ -34,15 +43,26 @@ "@types/mocha": "^10.0.1", "@types/node": "^18.0.3", "@types/node-fetch": "^2.6.1", + "@types/rewire": "^2.5.28", + "@types/seedrandom": "^3.0.5", + "@types/sinon": "^10.0.13", + "@types/supertest": "^2.0.12", "@types/ws": "^8.5.3", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "env-cmd": "^10.1.0", "eslint": "^8.34.0", + "json-schema-faker": "^0.5.0-rcv.46", "mocha": "^10.2.0", "nodemon": "^2.0.19", + "npm-run-all": "^4.1.5", "nyc": "^15.1.0", "prettier": "^2.7.1", + "randexp": "^0.5.3", + "rewire": "^6.0.0", + "seedrandom": "^3.0.5", + "sinon": "^15.0.2", + "supertest": "^6.3.3", "ts-mocha": "^10.0.0", "ts-node": "^10.9.1", "typescript": "^4.7.4" diff --git a/services/device/src/database/model.ts b/services/device/src/database/model.ts index e8598e63..59bcbb9e 100644 --- a/services/device/src/database/model.ts +++ b/services/device/src/database/model.ts @@ -41,7 +41,7 @@ export abstract class DeviceOverviewModel { @Column() type!: 'device' | 'group' | 'cloud instantiable' | 'edge instantiable' @Column({ nullable: true }) - owner?: string + owner!: string @DeleteDateColumn() deletedAt?: Date } diff --git a/services/device/src/database/repositories/device.ts b/services/device/src/database/repositories/device.ts index 956c9ee9..e407f847 100644 --- a/services/device/src/database/repositories/device.ts +++ b/services/device/src/database/repositories/device.ts @@ -1,4 +1,4 @@ -import { Device, DeviceInit, DeviceUpdate } from '../../generated/types' +import { Device, DeviceUpdate } from '../../generated/types' import { DeviceModel, DeviceOverviewModel } from '../model' import { concreteDeviceRepository } from './device/concreteDevice' import { deviceGroupRepository } from './device/deviceGroup' @@ -8,6 +8,7 @@ import { instantiableCloudDeviceRepository } from './device/instantiableCloudDev import { AbstractApplicationDataSource, AbstractRepository, + InvalidValueError, } from '@crosslab/service-common' export class DeviceRepository extends AbstractRepository< @@ -23,7 +24,7 @@ export class DeviceRepository extends AbstractRepository< this.repository = AppDataSource.getRepository(DeviceOverviewModel) } - async create(data?: DeviceInit<'request'>): Promise { + async create(data?: Device<'request'>): Promise { if (!this.repository) this.throwUninitializedRepositoryError() if (!data) return await super.create() @@ -42,12 +43,32 @@ export class DeviceRepository extends AbstractRepository< async write(model: DeviceModel, data: DeviceUpdate<'request'>): Promise { switch (model.type) { case 'cloud instantiable': + if (data.type !== model.type) + throw new InvalidValueError( + `Model of type ${model.type} cannot be updated with data of type ${data.type}`, + 400 + ) return await instantiableCloudDeviceRepository.write(model, data) case 'device': + if (data.type !== model.type) + throw new InvalidValueError( + `Model of type ${model.type} cannot be updated with data of type ${data.type}`, + 400 + ) return await concreteDeviceRepository.write(model, data) case 'edge instantiable': + if (data.type !== model.type) + throw new InvalidValueError( + `Model of type ${model.type} cannot be updated with data of type ${data.type}`, + 400 + ) return await instantiableBrowserDeviceRepository.write(model, data) case 'group': + if (data.type !== model.type) + throw new InvalidValueError( + `Model of type ${model.type} cannot be updated with data of type ${data.type}`, + 400 + ) return await deviceGroupRepository.write(model, data) } } diff --git a/services/device/src/database/repositories/device/concreteDevice.ts b/services/device/src/database/repositories/device/concreteDevice.ts index 43c3ebf3..8a23989d 100644 --- a/services/device/src/database/repositories/device/concreteDevice.ts +++ b/services/device/src/database/repositories/device/concreteDevice.ts @@ -1,8 +1,4 @@ -import { - ConcreteDevice, - ConcreteDeviceInit, - ConcreteDeviceUpdate, -} from '../../../generated/types' +import { ConcreteDevice, ConcreteDeviceUpdate } from '../../../generated/types' import { ConcreteDeviceModel } from '../../model' import { DeviceOverviewRepository } from './deviceOverview' import { @@ -23,7 +19,7 @@ export class ConcreteDeviceRepository extends AbstractRepository< this.repository = AppDataSource.getRepository(ConcreteDeviceModel) } - async create(data?: ConcreteDeviceInit<'request'>): Promise { + async create(data?: ConcreteDevice<'request'>): Promise { const model = await super.create(data) model.type = 'device' return model @@ -34,7 +30,6 @@ export class ConcreteDeviceRepository extends AbstractRepository< data: ConcreteDeviceUpdate<'request'> ): Promise { await DeviceOverviewRepository.write(model, data) - if (data.experiment) model.experiment = data.experiment if (data.services) model.services = data.services } @@ -43,7 +38,7 @@ export class ConcreteDeviceRepository extends AbstractRepository< return { ...(await DeviceOverviewRepository.format(model)), type: 'device', - announcedAvailability: model.announcedAvailability, + announcedAvailability: model.announcedAvailability ?? [], connected: model.connected, experiment: model.experiment, services: model.services, diff --git a/services/device/src/database/repositories/device/deviceGroup.ts b/services/device/src/database/repositories/device/deviceGroup.ts index 7ccaae2c..28968a88 100644 --- a/services/device/src/database/repositories/device/deviceGroup.ts +++ b/services/device/src/database/repositories/device/deviceGroup.ts @@ -1,7 +1,6 @@ import { Device, DeviceGroup, - DeviceGroupInit, DeviceGroupUpdate, DeviceReference, } from '../../../generated/types' @@ -26,7 +25,7 @@ export class DeviceGroupRepository extends AbstractRepository< this.repository = AppDataSource.getRepository(DeviceGroupModel) } - async create(data?: DeviceGroupInit<'request'>): Promise { + async create(data?: DeviceGroup<'request'>): Promise { const model = await super.create(data) model.type = 'group' return model diff --git a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts index 00a1ef35..456b2fbb 100644 --- a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts +++ b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts @@ -1,6 +1,5 @@ import { InstantiableBrowserDevice, - InstantiableBrowserDeviceInit, InstantiableBrowserDeviceUpdate, } from '../../../generated/types' import { InstantiableBrowserDeviceModel } from '../../model' @@ -24,7 +23,7 @@ export class InstantiableBrowserDeviceRepository extends AbstractRepository< } async create( - data?: InstantiableBrowserDeviceInit<'request'> + data?: InstantiableBrowserDevice<'request'> ): Promise { const model = await super.create(data) model.type = 'edge instantiable' diff --git a/services/device/src/database/repositories/device/instantiableCloudDevice.ts b/services/device/src/database/repositories/device/instantiableCloudDevice.ts index a5282af9..5aed1f0a 100644 --- a/services/device/src/database/repositories/device/instantiableCloudDevice.ts +++ b/services/device/src/database/repositories/device/instantiableCloudDevice.ts @@ -1,6 +1,5 @@ import { InstantiableCloudDevice, - InstantiableCloudDeviceInit, InstantiableCloudDeviceUpdate, } from '../../../generated/types' import { InstantiableCloudDeviceModel } from '../../model' @@ -24,7 +23,7 @@ export class InstantiableCloudDeviceRepository extends AbstractRepository< } async create( - data?: InstantiableCloudDeviceInit<'request'> + data?: InstantiableCloudDevice<'request'> ): Promise { const model = await super.create(data) model.type = 'cloud instantiable' diff --git a/services/device/src/operations/devices/device/patch.ts b/services/device/src/operations/devices/device/patch.ts index 99ee7a6e..7a997ad6 100644 --- a/services/device/src/operations/devices/device/patch.ts +++ b/services/device/src/operations/devices/device/patch.ts @@ -18,30 +18,30 @@ export const patchDevicesByDeviceId: patchDevicesByDeviceIdSignature = async ( ) => { console.log(`patchDevicesByDeviceId called`) - const device = await deviceRepository.findOneOrFail({ + const deviceModel = await deviceRepository.findOneOrFail({ where: { uuid: parameters.device_id }, }) - await deviceRepository.write(device, body ?? {}) - await deviceRepository.save(device) + await deviceRepository.write(deviceModel, body ?? { type: deviceModel.type }) + await deviceRepository.save(deviceModel) - await sendChangedCallback(device) + await sendChangedCallback(deviceModel) if (parameters.changedUrl) { console.log( `registering changed-callback for device '${deviceUrlFromId( - device.uuid + deviceModel.uuid )}' to '${parameters.changedUrl}'` ) - const changedCallbackURLs = changedCallbacks.get(device.uuid) ?? [] + const changedCallbackURLs = changedCallbacks.get(deviceModel.uuid) ?? [] changedCallbackURLs.push(parameters.changedUrl) - changedCallbacks.set(device.uuid, changedCallbackURLs) + changedCallbacks.set(deviceModel.uuid, changedCallbackURLs) } console.log(`patchDevicesByDeviceId succeeded`) return { status: 200, - body: await deviceRepository.format(device), + body: await deviceRepository.format(deviceModel), } } diff --git a/services/device/src/operations/devices/device/post.ts b/services/device/src/operations/devices/device/post.ts index c914eb20..88dd9ca0 100644 --- a/services/device/src/operations/devices/device/post.ts +++ b/services/device/src/operations/devices/device/post.ts @@ -1,11 +1,20 @@ import { deviceRepository } from '../../../database/repositories/device' import { concreteDeviceRepository } from '../../../database/repositories/device/concreteDevice' import { postDevicesByDeviceIdSignature } from '../../../generated/signatures' +import { ErrorWithStatus } from '../../../generated/types' import { apiClient } from '../../../globals' import { changedCallbacks } from '../../../methods/callbacks' import { deviceUrlFromId } from '../../../methods/urlFromId' import { ForbiddenOperationError } from '@crosslab/service-common' +// TODO: rethink how to handle this problem (required JWT user) +export class UnauthorizedError extends ErrorWithStatus { + constructor(message: string, status?: number) { + super(message, status) + this.name = 'UnauthorizedError' + } +} + /** * This function implements the functionality for handling POST requests on /devices/{device_id} endpoint. * @param parameters The parameters of the request. @@ -19,6 +28,9 @@ export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( ) => { console.log(`postDevicesByDeviceId called`) + // TODO: rethink how to handle this problem (required JWT user) + if (!user.JWT) throw new UnauthorizedError('User is not authorized') + const instantiableDeviceModel = await deviceRepository.findOneOrFail({ where: { uuid: parameters.device_id }, }) diff --git a/services/device/src/operations/devices/post.ts b/services/device/src/operations/devices/post.ts index fa73c79f..81ffa2a2 100644 --- a/services/device/src/operations/devices/post.ts +++ b/services/device/src/operations/devices/post.ts @@ -1,3 +1,4 @@ +import { UnauthorizedError } from '.' import { deviceRepository } from '../../database/repositories/device' import { postDevicesSignature } from '../../generated/signatures' import { changedCallbacks } from '../../methods/callbacks' @@ -11,6 +12,9 @@ import { changedCallbacks } from '../../methods/callbacks' export const postDevices: postDevicesSignature = async (parameters, body, user) => { console.log(`postDevices called`) + // TODO: rethink how to handle this problem (required JWT user) + if (!user.JWT) throw new UnauthorizedError('User is not authorized') + const deviceModel = await deviceRepository.create(body) deviceModel.owner = user.JWT?.url await deviceRepository.save(deviceModel) diff --git a/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts b/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts index b9c42748..82b690a9 100644 --- a/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts +++ b/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts @@ -1,4 +1,5 @@ import { ConcreteDeviceRepository } from '../../../../src/database/repositories/device/concreteDevice' +import { deviceUrlFromId } from '../../../../src/methods/urlFromId' import { EntityData } from '@crosslab/service-common' const uuid = '32348c89-f302-408f-8582-cb9783c74fbb' @@ -19,9 +20,10 @@ const concrete_device: EntityData = { name, description, owner, + announcedAvailability: [], }, response: { - url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', + url: deviceUrlFromId(uuid), type, name, description, diff --git a/services/device/test/data/devices/deviceGroups/device_group.spec.ts b/services/device/test/data/devices/deviceGroups/device_group.spec.ts index 5da31e90..46bf6cee 100644 --- a/services/device/test/data/devices/deviceGroups/device_group.spec.ts +++ b/services/device/test/data/devices/deviceGroups/device_group.spec.ts @@ -1,4 +1,6 @@ import { DeviceGroupRepository } from '../../../../src/database/repositories/device/deviceGroup' +import { deviceUrlFromId } from '../../../../src/methods/urlFromId' +import { concreteDeviceData } from '../concreteDevices/index.spec' import { EntityData } from '@crosslab/service-common' const uuid = 'd65b289a-44c5-452f-8c7b-e003714d3645' @@ -6,7 +8,7 @@ const type = 'group' const name = 'Device Group Example' const description = 'An example for a device group' const owner = 'http://localhost/users/superadmin' -const devices = [{ url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb' }] +const devices = [{ url: concreteDeviceData['concrete device'].response.url }] const device_group: EntityData = { request: { @@ -24,11 +26,11 @@ const device_group: EntityData = { owner, }, response: { - url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', + url: deviceUrlFromId(uuid), type, name, description, - devices, + devices: [concreteDeviceData['concrete device'].response], owner, }, } diff --git a/services/device/test/data/devices/instantiableBrowserDevices/instantiable_browser_device.spec.ts b/services/device/test/data/devices/instantiableBrowserDevices/instantiable_browser_device.spec.ts index 8f32f2b6..f2fb4c44 100644 --- a/services/device/test/data/devices/instantiableBrowserDevices/instantiable_browser_device.spec.ts +++ b/services/device/test/data/devices/instantiableBrowserDevices/instantiable_browser_device.spec.ts @@ -1,4 +1,5 @@ import { InstantiableBrowserDeviceRepository } from '../../../../src/database/repositories/device/instantiableBrowserDevice' +import { deviceUrlFromId } from '../../../../src/methods/urlFromId' import { EntityData } from '@crosslab/service-common' const uuid = '3742d2bd-8259-4dba-8908-f54dba68ba69' @@ -24,7 +25,7 @@ const instantiable_browser_device: EntityData = instantiateUrl, }, response: { - url: 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb', + url: deviceUrlFromId(uuid), type, name, description, diff --git a/services/device/test/data/peerconnections/example_peerconnection.spec.ts b/services/device/test/data/peerconnections/example_peerconnection.spec.ts index b327d7f6..9e5b6e2e 100644 --- a/services/device/test/data/peerconnections/example_peerconnection.spec.ts +++ b/services/device/test/data/peerconnections/example_peerconnection.spec.ts @@ -1,12 +1,12 @@ import { PeerconnectionRepository } from '../../../src/database/repositories/peerconnection' +import { peerconnectionUrlFromId } from '../../../src/methods/urlFromId' import { EntityData } from '@crosslab/service-common' const uuid = '184f5ada-84fe-4d33-ab7d-22801be1a4ff' -const url = `http://localhost/peeerconnections/${uuid}` const type = 'webrtc' const urlDeviceA = 'http://localhost/devices/32348c89-f302-408f-8582-cb9783c74fbb' const urlDeviceB = 'http://localhost/devices/aa3272e6-6f4e-4d5b-a4a9-252d9bac9bd3' -const status = 'waiting-for-devices' +const status = 'new' const example_peerconnection: EntityData = { request: { @@ -17,11 +17,11 @@ const example_peerconnection: EntityData = { uuid, type, status, - deviceA: { url: urlDeviceA }, - deviceB: { url: urlDeviceB }, + deviceA: { url: urlDeviceA, status: 'new' }, + deviceB: { url: urlDeviceB, status: 'new' }, }, response: { - url, + url: peerconnectionUrlFromId(uuid), type, status, devices: [{ url: urlDeviceA }, { url: urlDeviceB }], diff --git a/services/device/test/database/dataSource.spec.ts b/services/device/test/database/dataSource.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/services/device/test/database/model.spec.ts b/services/device/test/database/model.spec.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/services/device/test/database/repositories/device.spec.ts b/services/device/test/database/repositories/device.spec.ts index 587a9437..26f356d7 100644 --- a/services/device/test/database/repositories/device.spec.ts +++ b/services/device/test/database/repositories/device.spec.ts @@ -4,7 +4,7 @@ import { deviceRepository, DeviceRepository, } from '../../../src/database/repositories/device' -import { Device, DeviceInit, DeviceUpdate } from '../../../src/generated/types' +import { Device, DeviceUpdate } from '../../../src/generated/types' import { deviceData, DeviceName, deviceNames } from '../../data/devices/index.spec' import { concreteDeviceRepositoryTestSuite } from './device/concreteDevice.spec' import { deviceGroupRepositoryTestSuite } from './device/deviceGroup.spec' @@ -43,6 +43,7 @@ class DeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< `should write valid data to a model correctly (${key})`, async function () { const model = await data.repository.create({ + name: deviceData[key].request.name, type: deviceData[key].request.type, }) assert(data.validateCreate(model)) @@ -62,10 +63,7 @@ class DeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< }) } - validateCreate( - model: DeviceModel, - data?: DeviceInit<'request'> | undefined - ): boolean { + validateCreate(model: DeviceModel, data?: Device<'request'> | undefined): boolean { if (!data) return true switch (model.type) { @@ -176,34 +174,30 @@ class DeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< compareFormatted(first: Device<'response'>, second: Device<'response'>): boolean { switch (first.type) { case 'cloud instantiable': - assert(first.type === second.type) + if (!(first.type === second.type)) return false return instantiableCloudDeviceRepositoryTestSuite.compareFormatted( first, second ) case 'device': - assert(first.type === second.type) + if (!(first.type === second.type)) return false return concreteDeviceRepositoryTestSuite.compareFormatted(first, second) case 'edge instantiable': - assert(first.type === second.type) + if (!(first.type === second.type)) return false return instantiableBrowserDeviceRepositoryTestSuite.compareFormatted( first, second ) case 'group': - assert(first.type === second.type) + if (!(first.type === second.type)) return false return deviceGroupRepositoryTestSuite.compareFormatted(first, second) } } getFindOptionsWhere(model?: DeviceModel): FindOptionsWhere { - return model - ? { - uuid: model?.uuid, - } - : { - uuid: '', - } + return { + uuid: model ? model.uuid : 'non-existent', + } } } diff --git a/services/device/test/database/repositories/device/concreteDevice.spec.ts b/services/device/test/database/repositories/device/concreteDevice.spec.ts index 2b04a788..e4c1aac5 100644 --- a/services/device/test/database/repositories/device/concreteDevice.spec.ts +++ b/services/device/test/database/repositories/device/concreteDevice.spec.ts @@ -4,11 +4,7 @@ import { concreteDeviceRepository, ConcreteDeviceRepository, } from '../../../../src/database/repositories/device/concreteDevice' -import { - ConcreteDevice, - ConcreteDeviceInit, - ConcreteDeviceUpdate, -} from '../../../../src/generated/types' +import { ConcreteDevice, ConcreteDeviceUpdate } from '../../../../src/generated/types' import { ConcreteDeviceName } from '../../../data/devices/concreteDevices/index.spec' import { initTestDatabase } from '../index.spec' import { DeviceOverviewRepositoryTestSuite } from './deviceOverview.spec' @@ -31,7 +27,7 @@ class ConcreteDeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< validateCreate( model: ConcreteDeviceModel, - data?: ConcreteDeviceInit<'request'> + data?: ConcreteDevice<'request'> ): boolean { if (!data) return true @@ -58,10 +54,7 @@ class ConcreteDeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< data: ConcreteDevice<'response'> ): boolean { assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) - assert( - JSON.stringify(data.announcedAvailability) === - JSON.stringify(model.announcedAvailability) - ) + // TODO: validate announcedAvailability assert(data.connected === model.connected) assert(data.experiment === model.experiment) assert(JSON.stringify(data.services) === JSON.stringify(model.services)) @@ -102,28 +95,25 @@ class ConcreteDeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< first: ConcreteDevice<'response'>, second: ConcreteDevice<'response'> ): boolean { - assert(DeviceOverviewRepositoryTestSuite.compareFormatted(first, second)) - assert( + let isEqual = true + + isEqual &&= DeviceOverviewRepositoryTestSuite.compareFormatted(first, second) + isEqual &&= JSON.stringify(first.announcedAvailability) === - JSON.stringify(second.announcedAvailability) - ) - assert(first.connected === second.connected) - assert(first.experiment === second.experiment) - assert(JSON.stringify(first.services) === JSON.stringify(second.services)) + JSON.stringify(second.announcedAvailability) + isEqual &&= first.connected === second.connected + isEqual &&= first.experiment === second.experiment + isEqual &&= JSON.stringify(first.services) === JSON.stringify(second.services) - return true + return isEqual } getFindOptionsWhere( model?: ConcreteDeviceModel ): FindOptionsWhere { - return model - ? { - uuid: model?.uuid, - } - : { - uuid: '', - } + return { + uuid: model ? model.uuid : 'non-existent', + } } } diff --git a/services/device/test/database/repositories/device/deviceGroup.spec.ts b/services/device/test/database/repositories/device/deviceGroup.spec.ts index 3ede0a71..f3bdc7ac 100644 --- a/services/device/test/database/repositories/device/deviceGroup.spec.ts +++ b/services/device/test/database/repositories/device/deviceGroup.spec.ts @@ -4,11 +4,7 @@ import { deviceGroupRepository, DeviceGroupRepository, } from '../../../../src/database/repositories/device/deviceGroup' -import { - DeviceGroup, - DeviceGroupInit, - DeviceGroupUpdate, -} from '../../../../src/generated/types' +import { DeviceGroup, DeviceGroupUpdate } from '../../../../src/generated/types' import { DeviceGroupName } from '../../../data/devices/deviceGroups/index.spec' import { initTestDatabase } from '../index.spec' import { DeviceOverviewRepositoryTestSuite } from './deviceOverview.spec' @@ -29,7 +25,7 @@ class DeviceGroupRepositoryTestSuite extends AbstractRepositoryTestSuite< super(AppDataSource) } - validateCreate(model: DeviceGroupModel, data?: DeviceGroupInit<'request'>): boolean { + validateCreate(model: DeviceGroupModel, data?: DeviceGroup<'request'>): boolean { if (!data) return true assert(DeviceOverviewRepositoryTestSuite.validateCreate(model, data)) @@ -51,7 +47,7 @@ class DeviceGroupRepositoryTestSuite extends AbstractRepositoryTestSuite< validateFormat(model: DeviceGroupModel, data: DeviceGroup<'response'>): boolean { assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) - assert(JSON.stringify(data.devices) === JSON.stringify(model.devices)) // TODO + // TODO: validate devices return true } @@ -75,20 +71,18 @@ class DeviceGroupRepositoryTestSuite extends AbstractRepositoryTestSuite< first: DeviceGroup<'response'>, second: DeviceGroup<'response'> ): boolean { - assert(DeviceOverviewRepositoryTestSuite.compareFormatted(first, second)) - assert(JSON.stringify(first.devices) === JSON.stringify(second.devices)) + let isEqual = true - return true + isEqual &&= DeviceOverviewRepositoryTestSuite.compareFormatted(first, second) + isEqual &&= JSON.stringify(first.devices) === JSON.stringify(second.devices) + + return isEqual } getFindOptionsWhere(model?: DeviceGroupModel): FindOptionsWhere { - return model - ? { - uuid: model?.uuid, - } - : { - uuid: '', - } + return { + uuid: model ? model.uuid : 'non-existent', + } } } diff --git a/services/device/test/database/repositories/device/deviceOverview.spec.ts b/services/device/test/database/repositories/device/deviceOverview.spec.ts index fff6a281..e6814934 100644 --- a/services/device/test/database/repositories/device/deviceOverview.spec.ts +++ b/services/device/test/database/repositories/device/deviceOverview.spec.ts @@ -1,7 +1,7 @@ import { DeviceOverviewModel } from '../../../../src/database/model' import { DeviceOverviewRepository } from '../../../../src/database/repositories/device/deviceOverview' import { - DeviceInit, + Device, DeviceOverview, DeviceOverviewUpdate, } from '../../../../src/generated/types' @@ -14,10 +14,7 @@ export abstract class DeviceOverviewRepositoryTestSuite extends AbstractReposito DeviceName, DeviceOverviewRepository > { - static validateCreate( - model: DeviceOverviewModel, - data?: DeviceInit<'request'> - ): boolean { + static validateCreate(model: DeviceOverviewModel, data?: Device<'request'>): boolean { if (!data) return true assert(model.type === data.type) @@ -71,12 +68,14 @@ export abstract class DeviceOverviewRepositoryTestSuite extends AbstractReposito first: DeviceOverview<'response'>, second: DeviceOverview<'response'> ): boolean { - assert(first.description === second.description) - assert(first.name === second.name) - assert(first.owner === second.owner) - assert(first.type === second.type) - assert(first.url === second.url) + let isEqual = true - return true + isEqual &&= first.description === second.description + isEqual &&= first.name === second.name + isEqual &&= first.owner === second.owner + isEqual &&= first.type === second.type + isEqual &&= first.url === second.url + + return isEqual } } diff --git a/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts b/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts index 25baafd0..8ee51f73 100644 --- a/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts +++ b/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts @@ -6,7 +6,6 @@ import { } from '../../../../src/database/repositories/device/instantiableBrowserDevice' import { InstantiableBrowserDevice, - InstantiableBrowserDeviceInit, InstantiableBrowserDeviceUpdate, } from '../../../../src/generated/types' import { InstantiableBrowserDeviceName } from '../../../data/devices/instantiableBrowserDevices/index.spec' @@ -32,7 +31,7 @@ class InstantiableBrowserDeviceRepositoryTestSuite extends AbstractRepositoryTes validateCreate( model: InstantiableBrowserDeviceModel, - data?: InstantiableBrowserDeviceInit<'request'> + data?: InstantiableBrowserDevice<'request'> ): boolean { if (!data) return true @@ -90,23 +89,21 @@ class InstantiableBrowserDeviceRepositoryTestSuite extends AbstractRepositoryTes first: InstantiableBrowserDevice<'response'>, second: InstantiableBrowserDevice<'response'> ): boolean { - assert(DeviceOverviewRepositoryTestSuite.compareFormatted(first, second)) - assert(first.codeUrl === second.codeUrl) - assert(JSON.stringify(first.services) === JSON.stringify(second.services)) + let isEqual = true - return true + isEqual &&= DeviceOverviewRepositoryTestSuite.compareFormatted(first, second) + isEqual &&= first.codeUrl === second.codeUrl + isEqual &&= JSON.stringify(first.services) === JSON.stringify(second.services) + + return isEqual } getFindOptionsWhere( model?: InstantiableBrowserDeviceModel ): FindOptionsWhere { - return model - ? { - uuid: model?.uuid, - } - : { - uuid: '', - } + return { + uuid: model ? model.uuid : 'non-existent', + } } } diff --git a/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts b/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts index aa33ced6..c386fdca 100644 --- a/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts +++ b/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts @@ -6,7 +6,6 @@ import { } from '../../../../src/database/repositories/device/instantiableCloudDevice' import { InstantiableCloudDevice, - InstantiableCloudDeviceInit, InstantiableCloudDeviceUpdate, } from '../../../../src/generated/types' import { InstantiableCloudDeviceName } from '../../../data/devices/instantiableCloudDevices/index.spec' @@ -32,7 +31,7 @@ class InstantiableCloudDeviceRepositoryTestSuite extends AbstractRepositoryTestS validateCreate( model: InstantiableCloudDeviceModel, - data?: InstantiableCloudDeviceInit<'request'> + data?: InstantiableCloudDevice<'request'> ): boolean { if (!data) return true @@ -90,23 +89,21 @@ class InstantiableCloudDeviceRepositoryTestSuite extends AbstractRepositoryTestS first: InstantiableCloudDevice<'response'>, second: InstantiableCloudDevice<'response'> ): boolean { - assert(DeviceOverviewRepositoryTestSuite.compareFormatted(first, second)) - assert(first.instantiateUrl === second.instantiateUrl) - assert(JSON.stringify(first.services) === JSON.stringify(second.services)) + let isEqual = true - return true + isEqual &&= DeviceOverviewRepositoryTestSuite.compareFormatted(first, second) + isEqual &&= first.instantiateUrl === second.instantiateUrl + isEqual &&= JSON.stringify(first.services) === JSON.stringify(second.services) + + return isEqual } getFindOptionsWhere( model?: InstantiableCloudDeviceModel ): FindOptionsWhere { - return model - ? { - uuid: model?.uuid, - } - : { - uuid: '', - } + return { + uuid: model ? model.uuid : 'non-existent', + } } } diff --git a/services/device/test/database/repositories/index.spec.ts b/services/device/test/database/repositories/index.spec.ts index 2f8a9855..83c5cec3 100644 --- a/services/device/test/database/repositories/index.spec.ts +++ b/services/device/test/database/repositories/index.spec.ts @@ -14,10 +14,18 @@ import { deviceNames } from '../../data/devices/index.spec' import { prepareTestData, TestData } from '../../data/index.spec' import { peerconnectionNames } from '../../data/peerconnections/index.spec' import { deviceRepositoryTestSuite } from './device.spec' +import { concreteDeviceRepositoryTestSuite } from './device/concreteDevice.spec' +import { deviceGroupRepositoryTestSuite } from './device/deviceGroup.spec' +import { instantiableBrowserDeviceRepositoryTestSuite } from './device/instantiableBrowserDevice.spec' +import { instantiableCloudDeviceRepositoryTestSuite } from './device/instantiableCloudDevice.spec' import { peerconnectionRepositoryTestSuite } from './peerconnection.spec' import { DataSourceOptions } from 'typeorm' const repositoryTestSuites = [ + concreteDeviceRepositoryTestSuite, + deviceGroupRepositoryTestSuite, + instantiableBrowserDeviceRepositoryTestSuite, + instantiableCloudDeviceRepositoryTestSuite, deviceRepositoryTestSuite, peerconnectionRepositoryTestSuite, ] diff --git a/services/device/test/database/repositories/peerconnection.spec.ts b/services/device/test/database/repositories/peerconnection.spec.ts index ae71bde5..e971ad4c 100644 --- a/services/device/test/database/repositories/peerconnection.spec.ts +++ b/services/device/test/database/repositories/peerconnection.spec.ts @@ -5,9 +5,11 @@ import { PeerconnectionRepository, } from '../../../src/database/repositories/peerconnection' import { Peerconnection } from '../../../src/generated/types' +import { peerconnectionUrlFromId } from '../../../src/methods/urlFromId' import { PeerconnectionName } from '../../data/peerconnections/index.spec' import { initTestDatabase } from './index.spec' import { AbstractRepositoryTestSuite } from '@crosslab/service-common' +import assert from 'assert' import { FindOptionsWhere } from 'typeorm' class PeerconnectionRepositoryTestSuite extends AbstractRepositoryTestSuite< @@ -27,18 +29,42 @@ class PeerconnectionRepositoryTestSuite extends AbstractRepositoryTestSuite< model: PeerconnectionModel, data?: Peerconnection<'request'> ): boolean { - throw new Error('Method not implemented.') + if (!data) return true + + assert(this.validateWrite(model, data)) + + return true } validateWrite(model: PeerconnectionModel, data: Peerconnection<'request'>): boolean { - throw new Error('Method not implemented.') + if (data.devices) { + assert( + JSON.stringify(model.deviceA) === + JSON.stringify({ ...data.devices[0], status: 'new' }) + ) + assert( + JSON.stringify(model.deviceB) === + JSON.stringify({ ...data.devices[1], status: 'new' }) + ) + } + if (data.type) assert(model.type === data.type) + + return true } validateFormat( model: PeerconnectionModel, data: Peerconnection<'response'> ): boolean { - throw new Error('Method not implemented.') + assert( + JSON.stringify(data.devices) === + JSON.stringify([model.deviceA, model.deviceB]) + ) + assert(data.status === model.status) + assert(data.type === model.type) + assert(data.url === peerconnectionUrlFromId(model.uuid)) + + return true } compareModels( @@ -46,20 +72,39 @@ class PeerconnectionRepositoryTestSuite extends AbstractRepositoryTestSuite< secondModel: PeerconnectionModel, complete?: boolean ): boolean { - throw new Error('Method not implemented.') + const sameId = firstModel.uuid === secondModel.uuid + + if (!complete) return sameId + + assert(firstModel.deletedAt === secondModel.deletedAt) + assert(JSON.stringify(firstModel.deviceA) === JSON.stringify(secondModel.deviceA)) + assert(JSON.stringify(firstModel.deviceB) === JSON.stringify(secondModel.deviceB)) + assert(firstModel.status === secondModel.status) + assert(firstModel.type === secondModel.type) + + return true } compareFormatted( first: Peerconnection<'response'>, second: Peerconnection<'response'> ): boolean { - throw new Error('Method not implemented.') + let isEqual = true + + isEqual &&= JSON.stringify(first.devices) === JSON.stringify(second.devices) + isEqual &&= first.status === second.status + isEqual &&= first.type === second.type + isEqual &&= first.url === second.url + + return isEqual } getFindOptionsWhere( model?: PeerconnectionModel ): FindOptionsWhere { - throw new Error('Method not implemented.') + return { + uuid: model ? model.uuid : 'non-existent', + } } } diff --git a/services/device/test/methods/availability.spec.ts b/services/device/test/methods/availability.spec.ts index e69de29b..ef901b4e 100644 --- a/services/device/test/methods/availability.spec.ts +++ b/services/device/test/methods/availability.spec.ts @@ -0,0 +1,12 @@ +export default () => + describe('availability methods', function () { + describe('calculateAvailabilty', function () {}) + + describe('applyAvailabiltyRule', function () {}) + + describe('addTimeSlotsFromRule', function () {}) + + describe('sortTimeSlots', function () {}) + + describe('invertTimeSlots', function () {}) + }) diff --git a/services/device/test/methods/callbacks.spec.ts b/services/device/test/methods/callbacks.spec.ts index e69de29b..9795e611 100644 --- a/services/device/test/methods/callbacks.spec.ts +++ b/services/device/test/methods/callbacks.spec.ts @@ -0,0 +1,8 @@ +export default () => + describe('callbacks methods', function () { + describe('sendChangedCallback', function () {}) + + describe('sendClosedCallback', function () {}) + + describe('sendStatusChangedCallback', function () {}) + }) diff --git a/services/device/test/methods/signaling.spec.ts b/services/device/test/methods/signaling.spec.ts index e69de29b..4db7b969 100644 --- a/services/device/test/methods/signaling.spec.ts +++ b/services/device/test/methods/signaling.spec.ts @@ -0,0 +1,6 @@ +export default () => + describe('signaling methods', function () { + describe('SignalingQueue', function () {}) + + describe('startSignaling', function () {}) + }) diff --git a/services/device/test/methods/urlFromId.spec.ts b/services/device/test/methods/urlFromId.spec.ts index e69de29b..48fa7609 100644 --- a/services/device/test/methods/urlFromId.spec.ts +++ b/services/device/test/methods/urlFromId.spec.ts @@ -0,0 +1,6 @@ +export default () => + describe('urlFromId methods', function () { + describe('deviceUrlFromId', function () {}) + + describe('peerconnectionUrlFromId', function () {}) + }) diff --git a/services/device/test/operations/devices/device/availability/index.spec.ts b/services/device/test/operations/devices/device/availability/index.spec.ts index e69de29b..9cee774f 100644 --- a/services/device/test/operations/devices/device/availability/index.spec.ts +++ b/services/device/test/operations/devices/device/availability/index.spec.ts @@ -0,0 +1,3 @@ +import postSpec from './post.spec' + +export default [postSpec] diff --git a/services/device/test/operations/devices/device/availability/post.spec.ts b/services/device/test/operations/devices/device/availability/post.spec.ts index e69de29b..02fdb7e3 100644 --- a/services/device/test/operations/devices/device/availability/post.spec.ts +++ b/services/device/test/operations/devices/device/availability/post.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('POST /devices/{device_id}/availability', context) + + return suite +} diff --git a/services/device/test/operations/devices/device/delete.spec.ts b/services/device/test/operations/devices/device/delete.spec.ts index e69de29b..024dcd4e 100644 --- a/services/device/test/operations/devices/device/delete.spec.ts +++ b/services/device/test/operations/devices/device/delete.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('DELETE /devices/{device_id}', context) + + return suite +} diff --git a/services/device/test/operations/devices/device/get.spec.ts b/services/device/test/operations/devices/device/get.spec.ts index e69de29b..d4feba07 100644 --- a/services/device/test/operations/devices/device/get.spec.ts +++ b/services/device/test/operations/devices/device/get.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('GET /devices/{device_id}', context) + + return suite +} diff --git a/services/device/test/operations/devices/device/index.spec.ts b/services/device/test/operations/devices/device/index.spec.ts index e69de29b..b9a0bb96 100644 --- a/services/device/test/operations/devices/device/index.spec.ts +++ b/services/device/test/operations/devices/device/index.spec.ts @@ -0,0 +1,6 @@ +import deleteSpec from './delete.spec' +import getSpec from './get.spec' +import patchSpec from './patch.spec' +import postSpec from './post.spec' + +export default [deleteSpec, getSpec, patchSpec, postSpec] diff --git a/services/device/test/operations/devices/device/patch.spec.ts b/services/device/test/operations/devices/device/patch.spec.ts index e69de29b..df50cbb9 100644 --- a/services/device/test/operations/devices/device/patch.spec.ts +++ b/services/device/test/operations/devices/device/patch.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('PATCH /devices/{device_id}', context) + + return suite +} diff --git a/services/device/test/operations/devices/device/post.spec.ts b/services/device/test/operations/devices/device/post.spec.ts index e69de29b..9fc26b84 100644 --- a/services/device/test/operations/devices/device/post.spec.ts +++ b/services/device/test/operations/devices/device/post.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('POST /devices/{device_id}', context) + + return suite +} diff --git a/services/device/test/operations/devices/device/signaling/index.spec.ts b/services/device/test/operations/devices/device/signaling/index.spec.ts index e69de29b..9cee774f 100644 --- a/services/device/test/operations/devices/device/signaling/index.spec.ts +++ b/services/device/test/operations/devices/device/signaling/index.spec.ts @@ -0,0 +1,3 @@ +import postSpec from './post.spec' + +export default [postSpec] diff --git a/services/device/test/operations/devices/device/signaling/post.spec.ts b/services/device/test/operations/devices/device/signaling/post.spec.ts index e69de29b..e68b9a63 100644 --- a/services/device/test/operations/devices/device/signaling/post.spec.ts +++ b/services/device/test/operations/devices/device/signaling/post.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('POST /devices/{device_id}/signaling', context) + + return suite +} diff --git a/services/device/test/operations/devices/device/websocket/index.spec.ts b/services/device/test/operations/devices/device/websocket/index.spec.ts index e69de29b..9cee774f 100644 --- a/services/device/test/operations/devices/device/websocket/index.spec.ts +++ b/services/device/test/operations/devices/device/websocket/index.spec.ts @@ -0,0 +1,3 @@ +import postSpec from './post.spec' + +export default [postSpec] diff --git a/services/device/test/operations/devices/device/websocket/post.spec.ts b/services/device/test/operations/devices/device/websocket/post.spec.ts index e69de29b..675407ca 100644 --- a/services/device/test/operations/devices/device/websocket/post.spec.ts +++ b/services/device/test/operations/devices/device/websocket/post.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('POST /devices/{device_id}/websocket', context) + + return suite +} diff --git a/services/device/test/operations/devices/get.spec.ts b/services/device/test/operations/devices/get.spec.ts index e69de29b..9e2adc86 100644 --- a/services/device/test/operations/devices/get.spec.ts +++ b/services/device/test/operations/devices/get.spec.ts @@ -0,0 +1,32 @@ +import { getDevices } from '../../../src/operations/devices' +import { deviceNames } from '../../data/devices/index.spec' +import { TestData } from '../../data/index.spec' +import { DeviceOverviewRepositoryTestSuite } from '../../database/repositories/device/deviceOverview.spec' +import assert from 'assert' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('GET /devices', context) + + suite.addTest( + new Mocha.Test('should get all devices', async function () { + const result = await getDevices({}) + assert(result.status === 200) + + for (const deviceName of deviceNames) { + const searchedDevice = testData.devices[deviceName].response + assert( + result.body.find((device) => + DeviceOverviewRepositoryTestSuite.compareFormatted( + device, + searchedDevice + ) + ), + `could not find device '${deviceName}'` + ) + } + }) + ) + + return suite +} diff --git a/services/device/test/operations/devices/index.spec.ts b/services/device/test/operations/devices/index.spec.ts index e69de29b..1ac2862c 100644 --- a/services/device/test/operations/devices/index.spec.ts +++ b/services/device/test/operations/devices/index.spec.ts @@ -0,0 +1,4 @@ +import getSpec from './get.spec' +import postSpec from './post.spec' + +export default [getSpec, postSpec] diff --git a/services/device/test/operations/devices/post.spec.ts b/services/device/test/operations/devices/post.spec.ts index e69de29b..b10907aa 100644 --- a/services/device/test/operations/devices/post.spec.ts +++ b/services/device/test/operations/devices/post.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('POST /devices', context) + + return suite +} diff --git a/services/device/test/operations/index.spec.ts b/services/device/test/operations/index.spec.ts index e69de29b..01cff7e0 100644 --- a/services/device/test/operations/index.spec.ts +++ b/services/device/test/operations/index.spec.ts @@ -0,0 +1,36 @@ +import { AppDataSource } from '../../src/database/dataSource' +import { TestData } from '../data/index.spec' +import { initTestDatabase } from '../database/repositories/index.spec' +import deviceTests from './devices/index.spec' +import peerconnectionTests from './peerconnections/index.spec' + +const tests = [...deviceTests, ...peerconnectionTests] + +describe('Operations', function () { + let testData: TestData + let suite: Mocha.Suite = this + + this.beforeAll(async function () { + console.log = (_message: any, ..._optionalParams: any[]) => undefined + console.error = (_message: any, ..._optionalParams: any[]) => undefined + console.warn = (_message: any, ..._optionalParams: any[]) => undefined + console.info = (_message: any, ..._optionalParams: any[]) => undefined + testData = await initTestDatabase() + }) + + this.beforeEach(async function () { + if (AppDataSource.connected) { + await AppDataSource.teardown() + } + const newTestData = await initTestDatabase() + for (const key in newTestData) { + ;(testData as any)[key] = (newTestData as any)[key] + } + }) + + it('should initialize the test data', async function () { + for (const test of tests) { + suite.addSuite(test(suite.ctx, testData)) + } + }) +}) diff --git a/services/device/test/operations/peerconnections/get.spec.ts b/services/device/test/operations/peerconnections/get.spec.ts index e69de29b..2da5db25 100644 --- a/services/device/test/operations/peerconnections/get.spec.ts +++ b/services/device/test/operations/peerconnections/get.spec.ts @@ -0,0 +1,32 @@ +import { getPeerconnections } from '../../../src/operations/peerconnections' +import { TestData } from '../../data/index.spec' +import { peerconnectionNames } from '../../data/peerconnections/index.spec' +import { peerconnectionRepositoryTestSuite } from '../../database/repositories/peerconnection.spec' +import assert from 'assert' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('GET /peerconnections', context) + + suite.addTest( + new Mocha.Test('should get all peerconnections', async function () { + const result = await getPeerconnections({}) + assert(result.status === 200) + + for (const peerconnectionName of peerconnectionNames) { + const searchedPeerconnection = + testData.peerconnections[peerconnectionName].response + assert( + result.body.find((peerconnection) => + peerconnectionRepositoryTestSuite.compareFormatted( + peerconnection, + searchedPeerconnection + ) + ) + ) + } + }) + ) + + return suite +} diff --git a/services/device/test/operations/peerconnections/index.spec.ts b/services/device/test/operations/peerconnections/index.spec.ts index e69de29b..1ac2862c 100644 --- a/services/device/test/operations/peerconnections/index.spec.ts +++ b/services/device/test/operations/peerconnections/index.spec.ts @@ -0,0 +1,4 @@ +import getSpec from './get.spec' +import postSpec from './post.spec' + +export default [getSpec, postSpec] diff --git a/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts b/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts index e69de29b..efafe2a1 100644 --- a/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts +++ b/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('DELETE /peerconnections/{peerconnection_id}', context) + + return suite +} diff --git a/services/device/test/operations/peerconnections/peerconnection/device_status/index.spec.ts b/services/device/test/operations/peerconnections/peerconnection/device_status/index.spec.ts new file mode 100644 index 00000000..d28cf3d4 --- /dev/null +++ b/services/device/test/operations/peerconnections/peerconnection/device_status/index.spec.ts @@ -0,0 +1,3 @@ +import patchSpec from './patch.spec' + +export default [patchSpec] diff --git a/services/device/test/operations/peerconnections/peerconnection/device_status/patch.spec.ts b/services/device/test/operations/peerconnections/peerconnection/device_status/patch.spec.ts new file mode 100644 index 00000000..13e45076 --- /dev/null +++ b/services/device/test/operations/peerconnections/peerconnection/device_status/patch.spec.ts @@ -0,0 +1,11 @@ +import { TestData } from '../../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite( + 'PATCH /peerconnections/{peerconnection_id}/device_status', + context + ) + + return suite +} diff --git a/services/device/test/operations/peerconnections/peerconnection/get.spec.ts b/services/device/test/operations/peerconnections/peerconnection/get.spec.ts index e69de29b..480ab999 100644 --- a/services/device/test/operations/peerconnections/peerconnection/get.spec.ts +++ b/services/device/test/operations/peerconnections/peerconnection/get.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('GET /peerconnections/{peerconnection_id}', context) + + return suite +} diff --git a/services/device/test/operations/peerconnections/peerconnection/index.spec.ts b/services/device/test/operations/peerconnections/peerconnection/index.spec.ts index e69de29b..64c40ef7 100644 --- a/services/device/test/operations/peerconnections/peerconnection/index.spec.ts +++ b/services/device/test/operations/peerconnections/peerconnection/index.spec.ts @@ -0,0 +1,4 @@ +import deleteSpec from './delete.spec' +import getSpec from './get.spec' + +export default [deleteSpec, getSpec] diff --git a/services/device/test/operations/peerconnections/post.spec.ts b/services/device/test/operations/peerconnections/post.spec.ts index e69de29b..292aad7b 100644 --- a/services/device/test/operations/peerconnections/post.spec.ts +++ b/services/device/test/operations/peerconnections/post.spec.ts @@ -0,0 +1,8 @@ +import { TestData } from '../../data/index.spec' +import Mocha from 'mocha' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('POST /peerconnections', context) + + return suite +} From 6e5143dc711ca7778849c06fe67bf7fa8edc0154 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 27 Mar 2023 12:00:33 +0200 Subject: [PATCH 14/33] Update API --- services/openapi/dist/openapi.json | 153 +++++++++++++++++++++++------ 1 file changed, 122 insertions(+), 31 deletions(-) diff --git a/services/openapi/dist/openapi.json b/services/openapi/dist/openapi.json index ebdfe201..9f6eee0c 100644 --- a/services/openapi/dist/openapi.json +++ b/services/openapi/dist/openapi.json @@ -308,7 +308,9 @@ }, "required": [ "url", - "type" + "type", + "name", + "owner" ], "x-typeguard": true, "x-service-name": "Device Service" @@ -340,7 +342,8 @@ } }, "required": [ - "type" + "type", + "name" ], "x-service-name": "Device Service" }, @@ -549,10 +552,7 @@ "$ref": "#/components/schemas/service_description" } } - }, - "required": [ - "type" - ] + } } ], "x-typeguard": true, @@ -613,10 +613,7 @@ "$ref": "#/components/schemas/service_description" } } - }, - "required": [ - "type" - ] + } } ], "x-typeguard": true, @@ -644,10 +641,7 @@ "$ref": "#/components/schemas/service_description" } } - }, - "required": [ - "type" - ] + } } ], "x-typeguard": true, @@ -671,10 +665,7 @@ "$ref": "#/components/schemas/device_reference" } } - }, - "required": [ - "type" - ] + } } ], "x-typeguard": true, @@ -717,6 +708,7 @@ }, "device_cloud_instantiable_update": { "title": "Instantiable Cloud Device Update", + "type": "object", "allOf": [ { "$ref": "#/components/schemas/device_overview_update" @@ -739,10 +731,12 @@ } } ], + "additionalProperties": false, "x-service-name": "Device Service" }, "device_concrete_update": { "title": "Concrete Device Update", + "type": "object", "allOf": [ { "$ref": "#/components/schemas/device_overview_update" @@ -765,10 +759,12 @@ } } ], + "additionalProperties": false, "x-service-name": "Device Service" }, "device_edge_instantiable_update": { "title": "Instantiable Browser Device Update", + "type": "object", "allOf": [ { "$ref": "#/components/schemas/device_overview_update" @@ -791,10 +787,12 @@ } } ], + "additionalProperties": false, "x-service-name": "Device Service" }, "device_group_update": { "title": "Device Group Update", + "type": "object", "allOf": [ { "$ref": "#/components/schemas/device_overview_update" @@ -812,6 +810,7 @@ } } ], + "additionalProperties": false, "x-service-name": "Device Service" }, "device_update": { @@ -1060,6 +1059,20 @@ "x-typeguard": true, "x-service-name": "Device Service" }, + "peerconnection_status": { + "title": "Connection Status", + "type": "string", + "description": "The status of the peerconnection.", + "enum": [ + "new", + "connecting", + "connected", + "disconnected", + "failed", + "closed" + ], + "x-service-name": "Device Service" + }, "peerconnection_common": { "type": "object", "properties": { @@ -1076,8 +1089,15 @@ "local", "webrtc" ] + }, + "status": { + "$ref": "#/components/schemas/peerconnection_status" } }, + "required": [ + "url", + "type" + ], "x-service-name": "Device Service" }, "peerconnection_overview": { @@ -1097,7 +1117,10 @@ "$ref": "#/components/schemas/device_reference" } } - } + }, + "required": [ + "devices" + ] } ], "x-service-name": "Device Service" @@ -1144,19 +1167,11 @@ "items": { "$ref": "#/components/schemas/configured_device_reference" } - }, - "status": { - "type": "string", - "description": "The status of the peerconnection.", - "readOnly": true, - "enum": [ - "waiting-for-devices", - "connected", - "failed", - "closed" - ] } - } + }, + "required": [ + "devices" + ] } ], "x-typeguard": true, @@ -1494,6 +1509,17 @@ "f4c69c42-6e1c-44c3-8e44-f74bd22c3713" ] }, + "parameters-device_url": { + "in": "query", + "name": "device_url", + "description": "URL of the device", + "required": true, + "schema": { + "type": "string", + "format": "uri", + "x-service-name": "Device Service" + } + }, "experiment_id": { "in": "path", "name": "experiment_id", @@ -4818,6 +4844,71 @@ "x-service-name": "Device Service" } }, + "/peerconnections/{peerconnection_id}/device_status": { + "patch": { + "operationId": "patch_peerconnection_device_status", + "summary": "Sets the peerconnection status of a single device.", + "tags": [ + "peerconnection" + ], + "security": [ + { + "JWT": [ + "peerconnection", + "peerconnection:list" + ] + } + ], + "requestBody": { + "required": true, + "description": "The JSON Representation of the device peer connection.", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { + "$ref": "#/components/schemas/peerconnection_status" + } + }, + "required": [ + "status" + ] + } + } + } + }, + "responses": { + "201": { + "description": "OK." + }, + "400": { + "description": "Bad Request." + }, + "401": { + "description": "Unauthorized." + }, + "403": { + "description": "Forbidden." + }, + "404": { + "description": "Resource not found." + }, + "500": { + "description": "Server Error." + } + }, + "parameters": [ + { + "$ref": "#/components/parameters/peerconnection_id" + }, + { + "$ref": "#/components/parameters/parameters-device_url" + } + ], + "x-service-name": "Device Service" + } + }, "/experiments": { "get": { "operationId": "list_experiments", From ddc4e82b9a62479894fd9a27cda03a4d333fe6e6 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 27 Mar 2023 12:06:14 +0200 Subject: [PATCH 15/33] Update error status codes --- services/device/src/database/repositories/peerconnection.ts | 6 ++++-- .../src/operations/devices/device/availability/post.ts | 3 ++- services/device/src/operations/devices/device/post.ts | 6 +++--- services/device/src/operations/devices/post.ts | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/services/device/src/database/repositories/peerconnection.ts b/services/device/src/database/repositories/peerconnection.ts index 3f8d0ca8..abb7418b 100644 --- a/services/device/src/database/repositories/peerconnection.ts +++ b/services/device/src/database/repositories/peerconnection.ts @@ -35,7 +35,8 @@ export class PeerconnectionRepository extends AbstractRepository< if (data.devices && data.devices.length !== 2) { throw new InvalidValueError( - `Peerconnections need exactly 2 devices, received ${data.devices?.length}` + `Peerconnections need exactly 2 devices, received ${data.devices?.length}`, + 400 ) } @@ -45,7 +46,8 @@ export class PeerconnectionRepository extends AbstractRepository< if (!deviceA.url || !deviceB.url) { throw new InvalidValueError( - 'One of the provided devices does not have a url' + 'One of the provided devices does not have a url', + 400 ) } diff --git a/services/device/src/operations/devices/device/availability/post.ts b/services/device/src/operations/devices/device/availability/post.ts index 63ff56e7..4d2d75e1 100644 --- a/services/device/src/operations/devices/device/availability/post.ts +++ b/services/device/src/operations/devices/device/availability/post.ts @@ -23,7 +23,8 @@ export const postDevicesByDeviceIdAvailability: postDevicesByDeviceIdAvailabilit if (deviceModel.type !== 'device') { throw new ForbiddenOperationError( - `Can only update the availability for a device of type 'device', not for type '${deviceModel.type}'` + `Can only update the availability for a device of type 'device', not for type '${deviceModel.type}'`, + 400 ) } diff --git a/services/device/src/operations/devices/device/post.ts b/services/device/src/operations/devices/device/post.ts index 88dd9ca0..8748ff8c 100644 --- a/services/device/src/operations/devices/device/post.ts +++ b/services/device/src/operations/devices/device/post.ts @@ -29,7 +29,7 @@ export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( console.log(`postDevicesByDeviceId called`) // TODO: rethink how to handle this problem (required JWT user) - if (!user.JWT) throw new UnauthorizedError('User is not authorized') + if (!user.JWT) throw new UnauthorizedError('User is not authorized', 401) const instantiableDeviceModel = await deviceRepository.findOneOrFail({ where: { uuid: parameters.device_id }, @@ -40,9 +40,9 @@ export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( instantiableDeviceModel.type !== 'edge instantiable' ) throw new ForbiddenOperationError( - `Cannot create new instance of device ${deviceUrlFromId( + `Cannot create new instance of device '${deviceUrlFromId( instantiableDeviceModel.uuid - )} since it has type "${instantiableDeviceModel.type}"`, + )}' since it has type '${instantiableDeviceModel.type}'`, 400 ) diff --git a/services/device/src/operations/devices/post.ts b/services/device/src/operations/devices/post.ts index 81ffa2a2..f1d8c344 100644 --- a/services/device/src/operations/devices/post.ts +++ b/services/device/src/operations/devices/post.ts @@ -13,7 +13,7 @@ export const postDevices: postDevicesSignature = async (parameters, body, user) console.log(`postDevices called`) // TODO: rethink how to handle this problem (required JWT user) - if (!user.JWT) throw new UnauthorizedError('User is not authorized') + if (!user.JWT) throw new UnauthorizedError('User is not authorized', 401) const deviceModel = await deviceRepository.create(body) deviceModel.owner = user.JWT?.url From 9492d2d73885aa6dccabe2afd66f3053fd76322e Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 27 Mar 2023 12:49:58 +0200 Subject: [PATCH 16/33] Add config and urlFromId tests --- services/device/package.json | 18 ++- services/device/src/config.ts | 36 +++-- services/device/src/methods/urlFromId.ts | 15 +- services/device/test/config.spec.ts | 141 ++++++++++++++++++ services/device/test/index.spec.ts | 1 + services/device/test/methods/index.spec.ts | 19 +++ .../device/test/methods/urlFromId.spec.ts | 26 +++- 7 files changed, 225 insertions(+), 31 deletions(-) diff --git a/services/device/package.json b/services/device/package.json index f31ccdfd..2160c26a 100644 --- a/services/device/package.json +++ b/services/device/package.json @@ -13,23 +13,29 @@ "openapi-bundle": "npx --yes @redocly/cli bundle ./api/openapi.yml --output dist/openapi.json", "watch-openapi": "npx --yes chokidar-cli 'api/**/*.yml' -c 'npm run openapi-bundle'", "watch-rapidoc": "npx --yes browser-sync start --server --startPath 'api/rapidoc.html' --files 'dist/openapi.json'", + "build": "npm-run-all build:*", + "build:compile": "tsc --project tsconfig.build.json", + "build:generate": "npm-run-all build:generate:*", "build:generate:code": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service -o src/generated", "build:generate:test": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service:test -o test/generated", - "build:generate": "npm-run-all build:generate:*", - "build:compile": "tsc --project tsconfig.build.json", - "build": "npm-run-all build:*", "start": "node app/index.js", "dev": "env-cmd -e development npx nodemon src/index.ts", "format": "npx prettier src --write", "lint": "eslint .", + "test": "rm -rf coverage && rm -rf .nyc_output && npm-run-all -c test:*", + "test:index": "nyc --temp-dir .nyc_output/index --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/index.spec.ts", + "test:config": "nyc --temp-dir .nyc_output/config --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/config.spec.ts", + "test:methods": "nyc --temp-dir .nyc_output/methods --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/methods/index.spec.ts", "test:database": "nyc --temp-dir .nyc_output/database --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/database/index.spec.ts", "test:generated": "nyc --temp-dir .nyc_output/generated --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/generated/index.spec.ts", "test:operations": "nyc --temp-dir .nyc_output/operations --silent --reporter=html env-cmd -e development ts-mocha --require @babel/register test/operations/index.spec.ts", - "test": "rm -rf coverage && rm -rf .nyc_output && npm-run-all -c test:*", + "cov": "npm-run-all cov:* && nyc report --reporter=text --reporter=html", + "cov:index": "nyc merge .nyc_output/index .nyc_output/index.json", + "cov:config": "nyc merge .nyc_output/config .nyc_output/config.json", + "cov:methods": "nyc merge .nyc_output/methods .nyc_output/methods.json", "cov:database": "nyc merge .nyc_output/database .nyc_output/database.json", "cov:generated": "nyc merge .nyc_output/generated .nyc_output/generated.json", - "cov:operations": "nyc merge .nyc_output/operations .nyc_output/operations.json", - "cov": "npm-run-all cov:* && nyc report --reporter=text --reporter=html" + "cov:operations": "nyc merge .nyc_output/operations .nyc_output/operations.json" }, "author": "Johannes Nau", "license": "UNLICENSED", diff --git a/services/device/src/config.ts b/services/device/src/config.ts index f2c666d1..2e365301 100644 --- a/services/device/src/config.ts +++ b/services/device/src/config.ts @@ -10,26 +10,38 @@ import { import { exit } from 'process' import { DataSourceOptions } from 'typeorm' +export type AppConfiguration = { + PORT: number + NODE_ENV: string + BASE_URL: string + SECURITY_ISSUER: string + SECURITY_AUDIENCE: string +} + function die(reason: string): string { console.error(reason) exit(1) } -const PORT = parseInt(process.env.PORT ?? '3001') -const DEFAULT_BASE_URL = 'http://localhost:' + PORT +function initializeAppConfiguration(): AppConfiguration { + const PORT = parseInt(process.env.PORT ?? '3001') + const DEFAULT_BASE_URL = 'http://localhost:' + PORT -export const config = { - PORT: PORT, - NODE_ENV: process.env.NODE_ENV ?? 'development', - BASE_URL: process.env.BASE_URL ?? DEFAULT_BASE_URL, - SECURITY_ISSUER: - process.env.SECURITY_ISSUER ?? - die('the environment variable SECURITY_ISSUER is not defined!'), - SECURITY_AUDIENCE: - process.env.SECURITY_AUDIENCE ?? - die('the environment variable SECURITY_AUDIENCE is not defined!'), + return { + PORT: PORT, + NODE_ENV: process.env.NODE_ENV ?? 'development', + BASE_URL: process.env.BASE_URL ?? DEFAULT_BASE_URL, + SECURITY_ISSUER: + process.env.SECURITY_ISSUER ?? + die('the environment variable SECURITY_ISSUER is not defined!'), + SECURITY_AUDIENCE: + process.env.SECURITY_AUDIENCE ?? + die('the environment variable SECURITY_AUDIENCE is not defined!'), + } } +export const config = initializeAppConfiguration() + export const dataSourceConfig: DataSourceOptions = { type: 'sqlite', database: 'db/device.db', diff --git a/services/device/src/methods/urlFromId.ts b/services/device/src/methods/urlFromId.ts index ecd4a7f6..943e008d 100644 --- a/services/device/src/methods/urlFromId.ts +++ b/services/device/src/methods/urlFromId.ts @@ -6,12 +6,7 @@ import { config } from '../config' * @returns The url of the device. */ export function deviceUrlFromId(deviceÍd: string): string { - return ( - config.BASE_URL + - (config.BASE_URL.endsWith('/') ? '' : '/') + - 'devices/' + - deviceÍd - ) + return (config.BASE_URL + '/devices/' + deviceÍd).replace('//devices', '/devices') } /** @@ -20,10 +15,8 @@ export function deviceUrlFromId(deviceÍd: string): string { * @returns The url of the peerconnection. */ export function peerconnectionUrlFromId(peerconnectionId: string): string { - return ( - config.BASE_URL + - (config.BASE_URL.endsWith('/') ? '' : '/') + - 'peerconnections/' + - peerconnectionId + return (config.BASE_URL + '/peerconnections/' + peerconnectionId).replace( + '//peerconnections', + '/peerconnections' ) } diff --git a/services/device/test/config.spec.ts b/services/device/test/config.spec.ts index e69de29b..4f7c98ea 100644 --- a/services/device/test/config.spec.ts +++ b/services/device/test/config.spec.ts @@ -0,0 +1,141 @@ +import { AppConfiguration } from '../src/config' +import assert from 'assert' +import rewire from 'rewire' +import * as sinon from 'sinon' + +describe('Config', function () { + let initializeAppConfiguration: () => AppConfiguration + let die: (reason: string) => void + let processExitStub: sinon.SinonStub + let processEnvBackup: any + + this.beforeAll(function () { + this.timeout(0) + console.log = (_message: any, ..._optionalParams: any[]) => undefined + console.error = (_message: any, ..._optionalParams: any[]) => undefined + console.warn = (_message: any, ..._optionalParams: any[]) => undefined + console.info = (_message: any, ..._optionalParams: any[]) => undefined + const configModule = rewire('../src/config') + initializeAppConfiguration = configModule.__get__('initializeAppConfiguration') + die = configModule.__get__('die') + processExitStub = sinon.stub(process, 'exit') + processEnvBackup = JSON.parse(JSON.stringify(process.env)) + }) + + this.beforeEach(function () { + processExitStub.resetHistory() + }) + + this.afterAll(function () { + processExitStub.restore() + process.env = processEnvBackup + }) + + this.afterEach(function () { + process.env = processEnvBackup + }) + + describe('die', function () { + it('should exit the program and log the reason', async function () { + const TEST_REASON = 'test reason' + const consoleErrorStub = sinon.stub(console, 'error') + + die(TEST_REASON) + + assert(consoleErrorStub.calledWith(TEST_REASON)) + assert(processExitStub.calledWith(1)) + + consoleErrorStub.restore() + }) + }) + + it('should handle a valid PORT option correctly', async function () { + const TEST_PORT = '4000' + process.env.PORT = TEST_PORT + + const result = initializeAppConfiguration() + + assert(result.PORT === parseInt(TEST_PORT)) + }) + + it('should use the default PORT value when none is provided', async function () { + const DEFAULT_PORT = 3001 + delete process.env.PORT + + const result = initializeAppConfiguration() + + assert(result.PORT === DEFAULT_PORT) + }) + + it('should handle a valid NODE_ENV option correctly', async function () { + const TEST_NODE_ENV = 'production' + process.env.NODE_ENV = TEST_NODE_ENV + + const result = initializeAppConfiguration() + + assert(result.NODE_ENV === TEST_NODE_ENV) + }) + + it('should use the default NODE_ENV value when none is provided', async function () { + const DEFAULT_NODE_ENV = 'development' + delete process.env.NODE_ENV + + const result = initializeAppConfiguration() + + assert(result.NODE_ENV === DEFAULT_NODE_ENV) + }) + + it('should handle a valid BASE_URL option correctly', async function () { + const TEST_BASE_URL = 'http://localhost:4000' + process.env.BASE_URL = TEST_BASE_URL + + const result = initializeAppConfiguration() + + assert(result.BASE_URL === TEST_BASE_URL) + }) + + it('should use the default BASE_URL value when none is provided', async function () { + const DEFAULT_BASE_URL = 'http://localhost:3001' + delete process.env.BASE_URL + + const result = initializeAppConfiguration() + + assert(result.BASE_URL === DEFAULT_BASE_URL) + }) + + it('should handle a valid SECURITY_ISSUER option correctly', async function () { + const TEST_SECURITY_ISSUER = 'http://localhost' + process.env.SECURITY_ISSUER = TEST_SECURITY_ISSUER + + const result = initializeAppConfiguration() + + assert(result.SECURITY_ISSUER === TEST_SECURITY_ISSUER) + }) + + it('should exit if the SECURITY_ISSUER option is not set', async function () { + const EXPECTED_EXIT_CODE = 1 + delete process.env.SECURITY_ISSUER + + initializeAppConfiguration() + + assert(processExitStub.calledWith(EXPECTED_EXIT_CODE)) + }) + + it('should handle a valid SECURITY_AUDIENCE option correctly', async function () { + const TEST_SECURITY_AUDIENCE = 'http://localhost' + process.env.SECURITY_AUDIENCE = TEST_SECURITY_AUDIENCE + + const result = initializeAppConfiguration() + + assert(result.SECURITY_AUDIENCE === TEST_SECURITY_AUDIENCE) + }) + + it('should exit if the SECURITY_AUDIENCE option is not set', async function () { + const EXPECTED_EXIT_CODE = 1 + delete process.env.SECURITY_AUDIENCE + + initializeAppConfiguration() + + assert(processExitStub.calledWith(EXPECTED_EXIT_CODE)) + }) +}) diff --git a/services/device/test/index.spec.ts b/services/device/test/index.spec.ts index e69de29b..996ea078 100644 --- a/services/device/test/index.spec.ts +++ b/services/device/test/index.spec.ts @@ -0,0 +1 @@ +describe('Index', function () {}) diff --git a/services/device/test/methods/index.spec.ts b/services/device/test/methods/index.spec.ts index e69de29b..4a8e41a5 100644 --- a/services/device/test/methods/index.spec.ts +++ b/services/device/test/methods/index.spec.ts @@ -0,0 +1,19 @@ +import availabilitySpec from './availability.spec' +import callbacksSpec from './callbacks.spec' +import signalingSpec from './signaling.spec' +import urlFromIdSpec from './urlFromId.spec' + +const tests = [availabilitySpec, callbacksSpec, signalingSpec, urlFromIdSpec] + +describe('Methods', function () { + this.beforeAll(function () { + console.log = (_message: any, ..._optionalParams: any[]) => undefined + console.error = (_message: any, ..._optionalParams: any[]) => undefined + console.warn = (_message: any, ..._optionalParams: any[]) => undefined + console.info = (_message: any, ..._optionalParams: any[]) => undefined + }) + + for (const test of tests) { + test() + } +}) diff --git a/services/device/test/methods/urlFromId.spec.ts b/services/device/test/methods/urlFromId.spec.ts index 48fa7609..5d79a0c1 100644 --- a/services/device/test/methods/urlFromId.spec.ts +++ b/services/device/test/methods/urlFromId.spec.ts @@ -1,6 +1,28 @@ +import { config } from '../../src/config' +import { deviceUrlFromId, peerconnectionUrlFromId } from '../../src/methods/urlFromId' +import assert from 'assert' + export default () => describe('urlFromId methods', function () { - describe('deviceUrlFromId', function () {}) + describe('deviceUrlFromId', function () { + it('should correctly form the url of a device with a given id', function () { + const id = 'c85c2654-5961-4377-9b07-cbf7cdcfaf79' + const result = deviceUrlFromId(id) + + assert(result.startsWith(config.BASE_URL)) + assert(result.endsWith(`/devices/${id}`)) + assert(!result.endsWith(`//devices/${id}`)) + }) + }) + + describe('peerconnectionUrlFromId', function () { + it('should correctly form the url of a peerconnection with a given id', function () { + const id = '122cbea2-9f92-4179-a962-bdcf17c17149' + const result = peerconnectionUrlFromId(id) - describe('peerconnectionUrlFromId', function () {}) + assert(result.startsWith(config.BASE_URL)) + assert(result.endsWith(`/peerconnections/${id}`)) + assert(!result.endsWith(`//peerconnections/${id}`)) + }) + }) }) From e3b4527232440da609f781c7c093632aadd1496d Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 28 Mar 2023 12:24:50 +0200 Subject: [PATCH 17/33] Add tests for availability and callback methods --- .../availability/availability_rule.yml | 6 +- services/device/dist/openapi.json | 9 +- services/device/src/methods/availability.ts | 103 ++++---- services/device/src/methods/callbacks.ts | 26 +- .../device/test/methods/availability.spec.ts | 250 +++++++++++++++++- .../device/test/methods/callbacks.spec.ts | 205 +++++++++++++- 6 files changed, 519 insertions(+), 80 deletions(-) diff --git a/services/device/api/schemas/devices/availability/availability_rule.yml b/services/device/api/schemas/devices/availability/availability_rule.yml index 5c5920b6..e341e868 100644 --- a/services/device/api/schemas/devices/availability/availability_rule.yml +++ b/services/device/api/schemas/devices/availability/availability_rule.yml @@ -17,12 +17,12 @@ allOf: - HOURLY - DAILY - WEEKLY - - MONTHLY - - YEARLY until: description: Up to this date-time the time slot will be repeated. type: string format: date-time count: description: How often the time slot will be repeated - type: integer \ No newline at end of file + type: integer + required: + - frequency \ No newline at end of file diff --git a/services/device/dist/openapi.json b/services/device/dist/openapi.json index 983c5f2f..f9146fb7 100644 --- a/services/device/dist/openapi.json +++ b/services/device/dist/openapi.json @@ -467,9 +467,7 @@ "enum": [ "HOURLY", "DAILY", - "WEEKLY", - "MONTHLY", - "YEARLY" + "WEEKLY" ] }, "until": { @@ -481,7 +479,10 @@ "description": "How often the time slot will be repeated", "type": "integer" } - } + }, + "required": [ + "frequency" + ] } } } diff --git a/services/device/src/methods/availability.ts b/services/device/src/methods/availability.ts index 0e59ae71..ee52f83a 100644 --- a/services/device/src/methods/availability.ts +++ b/services/device/src/methods/availability.ts @@ -1,5 +1,5 @@ import { AvailabilityRule, TimeSlot } from '../generated/types' -import { RemoveIndex } from '@crosslab/service-common' +import { InvalidValueError, RemoveIndex } from '@crosslab/service-common' type TimeSlotModel = { start: number @@ -23,10 +23,13 @@ export function calculateAvailability( start: number, end: number ): Required[] { - let newAvailability: TimeSlotModel[] = [] + if (start > end) + throw new InvalidValueError("calculateAvailability called with 'start' > 'end'") + + let availability: TimeSlotModel[] = [] for (const availabilityRule of availabilityRules) { - newAvailability = applyAvailabilityRule( - newAvailability, + availability = applyAvailabilityRule( + availability, { ...availabilityRule, start: Date.parse(availabilityRule.start ?? ''), @@ -36,7 +39,7 @@ export function calculateAvailability( end ) } - return newAvailability.map((timeSlotModel) => { + return availability.map((timeSlotModel) => { return { start: new Date(timeSlotModel.start).toISOString(), end: new Date(timeSlotModel.end).toISOString(), @@ -109,17 +112,11 @@ function addTimeSlotsFromRule( JSON.stringify(availability, null, 4) ) const timeSlot: TimeSlotModel = { - start: - availabilityRule.start && availabilityRule.start >= start - ? availabilityRule.start - : start, - end: - availabilityRule.end && availabilityRule.end <= end - ? availabilityRule.end - : end, + start: availabilityRule.start || start, + end: availabilityRule.end || end, } - if (availabilityRule.repeat?.frequency && availabilityRule.end) { + if (availabilityRule.repeat) { let frequency = 0 switch (availabilityRule.repeat.frequency) { case 'HOURLY': @@ -131,57 +128,47 @@ function addTimeSlotsFromRule( case 'WEEKLY': frequency = 7 * 24 * 60 * 60 * 1000 break - case 'MONTHLY': - frequency = 28 * 7 * 24 * 60 * 60 * 1000 // not very precise since months vary in length - break - case 'YEARLY': - frequency = 365 * 7 * 24 * 60 * 60 * 1000 // not taking leap years into account - break - } - if (frequency < timeSlot.end - timeSlot.start) { - timeSlot.start = start - timeSlot.end = end } - const until = availabilityRule.repeat.until ?? end + const until = Date.parse(availabilityRule.repeat.until ?? '') || end let count = availabilityRule.repeat.count + if (frequency <= timeSlot.end - timeSlot.start && !count) { + timeSlot.end = until + } let currentTimeSlot: TimeSlotModel = { - start: - availabilityRule.start !== undefined - ? availabilityRule.start + frequency - : start, - end: availabilityRule.end + frequency, + start: timeSlot.start + frequency, + end: timeSlot.end + frequency, } - while (until < currentTimeSlot.end - frequency) { - if (until !== undefined) { - if (until < currentTimeSlot.start) break - if (!availabilityRule.start && until < currentTimeSlot.end - frequency) - break - } - if (count !== undefined) { - if (!count) break - count-- - } + while (until >= currentTimeSlot.start && until >= currentTimeSlot.end) { + if (count !== undefined && !count--) break - if (currentTimeSlot.start < start) currentTimeSlot.start = start - if (currentTimeSlot.end > end) currentTimeSlot.end = end availability.push(currentTimeSlot) - const newCurrentTimeSlot: TimeSlotModel = { - start: availabilityRule.start ? currentTimeSlot.start + frequency : start, + + currentTimeSlot = { + start: currentTimeSlot.start + frequency, end: currentTimeSlot.end + frequency, } - - currentTimeSlot = newCurrentTimeSlot } } availability.push(timeSlot) + console.log( 'availability after adding timeslots from rule:', JSON.stringify(availability, null, 4) ) return availability + .map((ts) => { + return { + start: Math.max(ts.start, start), + end: Math.min(ts.end, end), + } + }) + .filter((ts) => { + if (ts.start >= ts.end) return false + return true + }) } /** @@ -207,16 +194,28 @@ function sortTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { */ function mergeOverlappingTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { console.log('availability before merge:', JSON.stringify(availability, null, 4)) + + const mergedAvailability: TimeSlotModel[] = [] + let currentIndex = 0 for (let i = 0; i < availability.length; i++) { + if (mergedAvailability.length === 0) mergedAvailability.push(availability[i]) if (i < availability.length - 1) { - if (availability[i + 1].start <= availability[i].end) { - availability = availability.splice(i + 1, 1) - i-- + if (availability[i + 1].start <= mergedAvailability[currentIndex].end) { + mergedAvailability[currentIndex] = { + start: mergedAvailability[currentIndex].start, + end: + availability[i + 1].end > mergedAvailability[currentIndex].end + ? availability[i + 1].end + : mergedAvailability[currentIndex].end, + } + } else { + mergedAvailability.push(availability[i + 1]) + currentIndex++ } } } - console.log('availability after merge:', JSON.stringify(availability, null, 4)) - return availability + console.log('availability after merge:', JSON.stringify(mergedAvailability, null, 4)) + return mergedAvailability } /** @@ -263,7 +262,7 @@ function invertTimeSlots( // create last timeslot const lastTimeSlot: TimeSlotModel = { - start: availability[-1].end, + start: availability.reverse()[0].end, end, } diff --git a/services/device/src/methods/callbacks.ts b/services/device/src/methods/callbacks.ts index 53eb1540..a9790ca6 100644 --- a/services/device/src/methods/callbacks.ts +++ b/services/device/src/methods/callbacks.ts @@ -5,11 +5,13 @@ import { peerconnectionRepository } from '../database/repositories/peerconnectio import { deviceUrlFromId, peerconnectionUrlFromId } from './urlFromId' import fetch from 'node-fetch' -export const callbackUrl: string = - config.BASE_URL + (config.BASE_URL.endsWith('/') ? '' : '/') + 'callbacks/device' -export const changedCallbacks = new Map>() -export const closedCallbacks = new Map>() -export const statusChangedCallbacks = new Map>() +export const callbackUrl: string = (config.BASE_URL + '/callbacks/device').replace( + '//callbacks', + '/callbacks' +) +export const changedCallbacks = new Map() +export const closedCallbacks = new Map() +export const statusChangedCallbacks = new Map() /** * This function sends a 'device-changed' callback. @@ -35,10 +37,10 @@ export async function sendChangedCallback(device: DeviceModel) { }) if (res.status === 410) { - const changedCallbackURLs = changedCallbacks.get(device.uuid) ?? [] + const changedCallbackURLs = changedCallbacks.get(device.uuid) changedCallbacks.set( device.uuid, - changedCallbackURLs.filter((cb_url) => cb_url != url) + changedCallbackURLs?.filter((cb_url) => cb_url != url) ) } } @@ -57,6 +59,7 @@ export async function sendClosedCallback(peerconnection: PeerconnectionModel) { )}' to '${url}'` ) + // TODO: error handling const res = await fetch(url, { method: 'post', body: JSON.stringify({ @@ -68,10 +71,10 @@ export async function sendClosedCallback(peerconnection: PeerconnectionModel) { }) if (res.status === 410) { - const closedCallbackURLs = closedCallbacks.get(peerconnection.uuid) ?? [] + const closedCallbackURLs = closedCallbacks.get(peerconnection.uuid) closedCallbacks.set( peerconnection.uuid, - closedCallbackURLs.filter((cb_url) => cb_url != url) + closedCallbackURLs?.filter((cb_url) => cb_url != url) ) } } @@ -100,11 +103,10 @@ export async function sendStatusChangedCallback(peerconnection: PeerconnectionMo }) if (res.status === 410) { - const statusCallbackURLs = - statusChangedCallbacks.get(peerconnection.uuid) ?? [] + const statusCallbackURLs = statusChangedCallbacks.get(peerconnection.uuid) statusChangedCallbacks.set( peerconnection.uuid, - statusCallbackURLs.filter((cb_url) => cb_url != url) + statusCallbackURLs?.filter((cb_url) => cb_url != url) ) } } diff --git a/services/device/test/methods/availability.spec.ts b/services/device/test/methods/availability.spec.ts index ef901b4e..0db97579 100644 --- a/services/device/test/methods/availability.spec.ts +++ b/services/device/test/methods/availability.spec.ts @@ -1,12 +1,250 @@ +import { Availability, AvailabilityRule } from '../../src/generated/types' +import { calculateAvailability } from '../../src/methods/availability' +import { InvalidValueError } from '@crosslab/service-common' +import assert from 'assert' + export default () => describe('availability methods', function () { - describe('calculateAvailabilty', function () {}) - - describe('applyAvailabiltyRule', function () {}) + describe('calculateAvailabilty', function () { + it('should calculate the availability correctly', function () { + const start = 0 + const end = 1000000000 + const second = 1000 + const minute = 60 * second + const hour = 60 * minute + const day = 24 * hour + const week = 7 * day - describe('addTimeSlotsFromRule', function () {}) + const datasets: { + rules: AvailabilityRule[] + availability: Availability + }[] = [ + { + rules: [], + availability: [], + }, + { + rules: [{ available: true }], + availability: [ + { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + }, + ], + }, + { + rules: [{ available: false }], + availability: [], + }, + { + rules: [ + { + available: true, + start: new Date(100).toISOString(), + end: new Date(200).toISOString(), + }, + ], + availability: [ + { + start: new Date(100).toISOString(), + end: new Date(200).toISOString(), + }, + ], + }, + { + rules: [ + { + available: true, + start: new Date(100).toISOString(), + end: new Date(200).toISOString(), + repeat: { + frequency: 'HOURLY', + until: new Date(end / 2).toISOString(), + count: 10, + }, + }, + ], + availability: Array.from(Array(11).keys()).map((n) => { + return { + start: new Date(n * hour + 100).toISOString(), + end: new Date(n * hour + 200).toISOString(), + } + }), + }, + { + rules: [ + { + available: true, + start: new Date(100).toISOString(), + end: new Date(200).toISOString(), + repeat: { + frequency: 'DAILY', + until: new Date(end / 2).toISOString(), + count: 10, + }, + }, + ], + availability: Array.from(Array(6).keys()).map((n) => { + return { + start: new Date(n * day + 100).toISOString(), + end: new Date(n * day + 200).toISOString(), + } + }), + }, + { + rules: [ + { + available: true, + start: new Date(100).toISOString(), + end: new Date(200).toISOString(), + repeat: { + frequency: 'WEEKLY', + until: new Date(week + 199).toISOString(), + count: 10, + }, + }, + ], + availability: [ + { + start: new Date(100).toISOString(), + end: new Date(200).toISOString(), + }, + ], + }, + { + rules: [ + { + available: true, + start: new Date(100).toISOString(), + end: new Date(200).toISOString(), + repeat: { + frequency: 'WEEKLY', + until: new Date(week + 200).toISOString(), + count: 10, + }, + }, + ], + availability: [ + { + start: new Date(100).toISOString(), + end: new Date(200).toISOString(), + }, + { + start: new Date(week + 100).toISOString(), + end: new Date(week + 200).toISOString(), + }, + ], + }, + { + rules: [ + { + available: true, + start: new Date(100).toISOString(), + end: new Date(200).toISOString(), + repeat: { + frequency: 'WEEKLY', + until: new Date(week + 200).toISOString(), + }, + }, + { + available: true, + start: new Date(100).toISOString(), + end: new Date(300).toISOString(), + }, + { + available: true, + start: new Date(100).toISOString(), + end: new Date(150).toISOString(), + }, + { + start: new Date(3000).toISOString(), + end: new Date(3000).toISOString(), + }, + { + start: new Date(3000).toISOString(), + end: new Date(2500).toISOString(), + }, + ], + availability: [ + { + start: new Date(100).toISOString(), + end: new Date(300).toISOString(), + }, + { + start: new Date(week + 100).toISOString(), + end: new Date(week + 200).toISOString(), + }, + ], + }, + { + rules: [ + { + available: true, + start: new Date(1000).toISOString(), + end: new Date(1000 + hour).toISOString(), + repeat: { frequency: 'HOURLY' }, + }, + ], + availability: [ + { + start: new Date(1000).toISOString(), + end: new Date(end).toISOString(), + }, + ], + }, + { + rules: [ + { + available: true, + start: new Date(1000).toISOString(), + end: new Date(6000).toISOString(), + }, + { + available: false, + start: new Date(2000).toISOString(), + end: new Date(5000).toISOString(), + }, + { + start: new Date(3000).toISOString(), + end: new Date(4000).toISOString(), + }, + ], + availability: [ + { + start: new Date(1000).toISOString(), + end: new Date(2000).toISOString(), + }, + { + start: new Date(3000).toISOString(), + end: new Date(4000).toISOString(), + }, + { + start: new Date(5000).toISOString(), + end: new Date(6000).toISOString(), + }, + ], + }, + ] - describe('sortTimeSlots', function () {}) + for (const [index, dataset] of datasets.entries()) { + const result = calculateAvailability(dataset.rules, start, end) + assert( + JSON.stringify(result) === JSON.stringify(dataset.availability), + `An error occurred in dataset ${index}: \n ${JSON.stringify( + dataset, + null, + 4 + ).replace(/\n/g, '\n ')}` + ) + } + }) - describe('invertTimeSlots', function () {}) + it('should throw an InvalidValueError if start > end', function () { + try { + calculateAvailability([], 100, 50) + } catch (error) { + assert(error instanceof InvalidValueError) + } + }) + }) }) diff --git a/services/device/test/methods/callbacks.spec.ts b/services/device/test/methods/callbacks.spec.ts index 9795e611..8861916d 100644 --- a/services/device/test/methods/callbacks.spec.ts +++ b/services/device/test/methods/callbacks.spec.ts @@ -1,8 +1,207 @@ +import { DeviceModel, PeerconnectionModel } from '../../src/database/model' +import { + changedCallbacks, + closedCallbacks, + sendChangedCallback, + sendClosedCallback, + sendStatusChangedCallback, + statusChangedCallbacks, +} from '../../src/methods/callbacks' +import assert from 'assert' +import * as fetchModule from 'node-fetch' +import * as sinon from 'sinon' + export default () => describe('callbacks methods', function () { - describe('sendChangedCallback', function () {}) + let CALLBACK_URLS: string[] + let TEST_DEVICE_MODEL: DeviceModel + let TEST_PEERCONNECTION_MODEL: PeerconnectionModel + let fetchStub: sinon.SinonStub< + Parameters, + Partial> + > + + this.beforeAll(function () { + CALLBACK_URLS = [ + 'http://localhost/callback/1', + 'http://localhost/callback/2', + 'http://localhost/callback/3', + ] + TEST_DEVICE_MODEL = { + type: 'device', + uuid: 'ea2a852d-b16c-45e0-819f-0af793bb596e', + name: 'Test Device', + owner: 'http://localhost', + } + TEST_PEERCONNECTION_MODEL = { + uuid: 'ea2a852d-b16c-45e0-819f-0af793bb596e', + type: 'webrtc', + status: 'new', + deviceA: { url: 'http://localhost/devices/a', status: 'new' }, + deviceB: { url: 'http://localhost/devices/b', status: 'new' }, + } + fetchStub = sinon.stub(fetchModule, 'default') + }) + + this.afterEach(function () { + fetchStub.reset() + }) + + this.afterAll(function () { + fetchStub.restore() + }) + + describe('sendChangedCallback', function () { + it('should not send anything if no callback urls are registered', async function () { + assert(!changedCallbacks.get(TEST_DEVICE_MODEL.uuid)) + + await sendChangedCallback(TEST_DEVICE_MODEL) + + assert(!fetchStub.called) + }) + + it('should send callback message to each registered callback url', async function () { + changedCallbacks.set(TEST_DEVICE_MODEL.uuid, CALLBACK_URLS) + + fetchStub.resolves({ + status: 200, + }) + + await sendChangedCallback(TEST_DEVICE_MODEL) + + assert(fetchStub.callCount === CALLBACK_URLS.length) + assert( + JSON.stringify(changedCallbacks.get(TEST_DEVICE_MODEL.uuid)) === + JSON.stringify(CALLBACK_URLS) + ) + }) + + it('should remove callback url on 410 response', async function () { + changedCallbacks.set(TEST_DEVICE_MODEL.uuid, CALLBACK_URLS) + + fetchStub.onFirstCall().resolves({ + status: 410, + }) + + fetchStub.onSecondCall().resolves({ + status: 200, + }) + + fetchStub.onThirdCall().resolves({ + status: 410, + }) + + await sendChangedCallback(TEST_DEVICE_MODEL) + + assert(fetchStub.callCount === CALLBACK_URLS.length) + assert( + JSON.stringify(changedCallbacks.get(TEST_DEVICE_MODEL.uuid)) === + JSON.stringify([CALLBACK_URLS[1]]) + ) + }) + }) + + describe('sendClosedCallback', function () { + it('should not send anything if no callback urls are registered', async function () { + assert(!closedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid)) + + await sendClosedCallback(TEST_PEERCONNECTION_MODEL) + + assert(!fetchStub.called) + }) + + it('should send callback message to each registered callback url', async function () { + closedCallbacks.set(TEST_PEERCONNECTION_MODEL.uuid, CALLBACK_URLS) + + fetchStub.resolves({ + status: 200, + }) + + await sendClosedCallback(TEST_PEERCONNECTION_MODEL) + + assert(fetchStub.callCount === CALLBACK_URLS.length) + assert( + JSON.stringify( + closedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid) + ) === JSON.stringify(CALLBACK_URLS) + ) + }) + + it('should remove callback url on 410 response', async function () { + closedCallbacks.set(TEST_PEERCONNECTION_MODEL.uuid, CALLBACK_URLS) + + fetchStub.onFirstCall().resolves({ + status: 410, + }) + + fetchStub.onSecondCall().resolves({ + status: 200, + }) + + fetchStub.onThirdCall().resolves({ + status: 410, + }) + + await sendClosedCallback(TEST_PEERCONNECTION_MODEL) + + assert(fetchStub.callCount === CALLBACK_URLS.length) + assert( + JSON.stringify( + closedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid) + ) === JSON.stringify([CALLBACK_URLS[1]]) + ) + }) + }) + + describe('sendStatusChangedCallback', function () { + it('should not send anything if no callback urls are registered', async function () { + assert(!statusChangedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid)) + + await sendStatusChangedCallback(TEST_PEERCONNECTION_MODEL) + + assert(!fetchStub.called) + }) + + it('should send callback message to each registered callback url', async function () { + statusChangedCallbacks.set(TEST_PEERCONNECTION_MODEL.uuid, CALLBACK_URLS) + + fetchStub.resolves({ + status: 200, + }) + + await sendStatusChangedCallback(TEST_PEERCONNECTION_MODEL) + + assert(fetchStub.callCount === CALLBACK_URLS.length) + assert( + JSON.stringify( + statusChangedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid) + ) === JSON.stringify(CALLBACK_URLS) + ) + }) + + it('should remove callback url on 410 response', async function () { + statusChangedCallbacks.set(TEST_PEERCONNECTION_MODEL.uuid, CALLBACK_URLS) + + fetchStub.onFirstCall().resolves({ + status: 410, + }) + + fetchStub.onSecondCall().resolves({ + status: 200, + }) + + fetchStub.onThirdCall().resolves({ + status: 410, + }) - describe('sendClosedCallback', function () {}) + await sendStatusChangedCallback(TEST_PEERCONNECTION_MODEL) - describe('sendStatusChangedCallback', function () {}) + assert(fetchStub.callCount === CALLBACK_URLS.length) + assert( + JSON.stringify( + statusChangedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid) + ) === JSON.stringify([CALLBACK_URLS[1]]) + ) + }) + }) }) From b90b8478c6f00b6af95a83df40c8d7af1855a3e5 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 28 Mar 2023 18:41:27 +0200 Subject: [PATCH 18/33] Add callbacks methods tests --- services/device/src/methods/callbacks.ts | 9 ++- .../device/test/methods/callbacks.spec.ts | 60 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/services/device/src/methods/callbacks.ts b/services/device/src/methods/callbacks.ts index a9790ca6..062ad7c6 100644 --- a/services/device/src/methods/callbacks.ts +++ b/services/device/src/methods/callbacks.ts @@ -26,6 +26,7 @@ export async function sendChangedCallback(device: DeviceModel) { )}' to '${url}'` ) + // TODO: error handling const res = await fetch(url, { method: 'POST', body: JSON.stringify({ @@ -61,10 +62,10 @@ export async function sendClosedCallback(peerconnection: PeerconnectionModel) { // TODO: error handling const res = await fetch(url, { - method: 'post', + method: 'POST', body: JSON.stringify({ callbackType: 'event', - eventType: 'peerconnnection-closed', + eventType: 'peerconnection-closed', peerconnection: await peerconnectionRepository.format(peerconnection), }), headers: [['Content-Type', 'application/json']], @@ -92,8 +93,10 @@ export async function sendStatusChangedCallback(peerconnection: PeerconnectionMo peerconnection.uuid )}' to '${url}'` ) + + // TODO: error handling const res = await fetch(url, { - method: 'post', + method: 'POST', body: JSON.stringify({ callbackType: 'event', eventType: 'peerconnection-status-changed', diff --git a/services/device/test/methods/callbacks.spec.ts b/services/device/test/methods/callbacks.spec.ts index 8861916d..5eb7b8bf 100644 --- a/services/device/test/methods/callbacks.spec.ts +++ b/services/device/test/methods/callbacks.spec.ts @@ -1,4 +1,6 @@ import { DeviceModel, PeerconnectionModel } from '../../src/database/model' +import { deviceRepository } from '../../src/database/repositories/device' +import { peerconnectionRepository } from '../../src/database/repositories/peerconnection' import { changedCallbacks, closedCallbacks, @@ -51,6 +53,58 @@ export default () => fetchStub.restore() }) + async function checkArgsDevice() { + for (let i = 0; i < fetchStub.callCount; i++) { + assert(fetchStub.args[i][0] === CALLBACK_URLS[i]) + assert(fetchStub.args[i][1]?.method === 'POST') + assert( + fetchStub.args[i][1]?.body === + JSON.stringify({ + callbackType: 'event', + eventType: 'device-changed', + device: await deviceRepository.format(TEST_DEVICE_MODEL), + }) + ) + const headers = fetchStub.args[i][1]?.headers + await checkHeaders(headers) + } + } + + async function checkArgsPeerconnection( + eventType: 'peerconnection-closed' | 'peerconnection-status-changed' + ) { + for (let i = 0; i < fetchStub.callCount; i++) { + assert(fetchStub.args[i][0] === CALLBACK_URLS[i]) + assert(fetchStub.args[i][1]?.method === 'POST') + assert( + fetchStub.args[i][1]?.body === + JSON.stringify({ + callbackType: 'event', + eventType, + peerconnection: await peerconnectionRepository.format( + TEST_PEERCONNECTION_MODEL + ), + }) + ) + const headers = fetchStub.args[i][1]?.headers + await checkHeaders(headers) + } + } + + async function checkHeaders(headers?: fetchModule.HeadersInit | undefined) { + assert(headers) + assert(typeof headers.values !== 'string') + const headersValues = headers.values() + const firstHeader = headersValues.next() + assert(Array.isArray(firstHeader.value)) + assert(!firstHeader.done) + assert(firstHeader.value.length === 2) + assert(firstHeader.value[0] === 'Content-Type') + assert(firstHeader.value[1] === 'application/json') + const secondHeader = headersValues.next() + assert(secondHeader.done && secondHeader.value === undefined) + } + describe('sendChangedCallback', function () { it('should not send anything if no callback urls are registered', async function () { assert(!changedCallbacks.get(TEST_DEVICE_MODEL.uuid)) @@ -74,6 +128,7 @@ export default () => JSON.stringify(changedCallbacks.get(TEST_DEVICE_MODEL.uuid)) === JSON.stringify(CALLBACK_URLS) ) + await checkArgsDevice() }) it('should remove callback url on 410 response', async function () { @@ -98,6 +153,7 @@ export default () => JSON.stringify(changedCallbacks.get(TEST_DEVICE_MODEL.uuid)) === JSON.stringify([CALLBACK_URLS[1]]) ) + await checkArgsDevice() }) }) @@ -125,6 +181,7 @@ export default () => closedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid) ) === JSON.stringify(CALLBACK_URLS) ) + await checkArgsPeerconnection('peerconnection-closed') }) it('should remove callback url on 410 response', async function () { @@ -150,6 +207,7 @@ export default () => closedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid) ) === JSON.stringify([CALLBACK_URLS[1]]) ) + await checkArgsPeerconnection('peerconnection-closed') }) }) @@ -177,6 +235,7 @@ export default () => statusChangedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid) ) === JSON.stringify(CALLBACK_URLS) ) + await checkArgsPeerconnection('peerconnection-status-changed') }) it('should remove callback url on 410 response', async function () { @@ -202,6 +261,7 @@ export default () => statusChangedCallbacks.get(TEST_PEERCONNECTION_MODEL.uuid) ) === JSON.stringify([CALLBACK_URLS[1]]) ) + await checkArgsPeerconnection('peerconnection-status-changed') }) }) }) From e27d71f41a0cd370552d2b61fff586e3eb35ef3b Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 28 Mar 2023 21:18:18 +0200 Subject: [PATCH 19/33] Add signaling methods tests --- services/device/src/methods/signaling.ts | 17 +- .../device/test/methods/signaling.spec.ts | 198 +++++++++++++++++- 2 files changed, 205 insertions(+), 10 deletions(-) diff --git a/services/device/src/methods/signaling.ts b/services/device/src/methods/signaling.ts index 57c64744..89b2d619 100644 --- a/services/device/src/methods/signaling.ts +++ b/services/device/src/methods/signaling.ts @@ -1,5 +1,5 @@ -import { AppDataSource } from '../database/dataSource' import { PeerconnectionModel } from '../database/model' +import { peerconnectionRepository } from '../database/repositories/peerconnection' import { CreatePeerconnectionMessage } from '../generated/types' import { apiClient } from '../globals' import { peerconnectionUrlFromId } from './urlFromId' @@ -24,6 +24,10 @@ class SignalingQueue { } }) } + + public isEmpty(): boolean { + return this.queue.length === 0 + } } export const signalingQueue = new SignalingQueue() @@ -36,7 +40,6 @@ export const signalingQueue = new SignalingQueue() async function startSignaling(peerconnectionId: string) { console.log(`Starting signaling for ${peerconnectionId}`) - const peerconnectionRepository = AppDataSource.getRepository(PeerconnectionModel) const peerconnectionModel = await peerconnectionRepository.findOneOrFail({ where: { uuid: peerconnectionId, @@ -63,23 +66,19 @@ async function startSignaling(peerconnectionId: string) { const common = { messageType: 'command', command: 'createPeerconnection', - connectionType: 'webrtc', + connectionType: peerconnectionModel.type, connectionUrl: peerconnectionUrlFromId(peerconnectionModel.uuid), } const createPeerConnectionMessageA: CreatePeerconnectionMessage = { ...common, - services: peerconnectionModel.deviceA.config?.services - ? peerconnectionModel.deviceA.config.services - : [], + services: peerconnectionModel.deviceA.config?.services ?? [], tiebreaker: false, } const createPeerConnectionMessageB: CreatePeerconnectionMessage = { ...common, - services: peerconnectionModel.deviceB.config?.services - ? peerconnectionModel.deviceB.config.services - : [], + services: peerconnectionModel.deviceB.config?.services ?? [], tiebreaker: true, } diff --git a/services/device/test/methods/signaling.spec.ts b/services/device/test/methods/signaling.spec.ts index 4db7b969..1ea6d835 100644 --- a/services/device/test/methods/signaling.spec.ts +++ b/services/device/test/methods/signaling.spec.ts @@ -1,6 +1,202 @@ +import { PeerconnectionModel } from '../../src/database/model' +import { peerconnectionRepository } from '../../src/database/repositories/peerconnection' +import { apiClient } from '../../src/globals' +import { signalingQueue } from '../../src/methods/signaling' +import { peerconnectionUrlFromId } from '../../src/methods/urlFromId' +import assert from 'assert' +import seedrandom from 'seedrandom' +import * as sinon from 'sinon' + export default () => describe('signaling methods', function () { - describe('SignalingQueue', function () {}) + describe('signalingQueue', function () { + let peerconnectionModels: (PeerconnectionModel & { + signalingStarted: boolean + })[] + let findOneOrFailStub: sinon.SinonStub< + Parameters, + ReturnType + > + let saveStub: sinon.SinonStub< + Parameters, + ReturnType + > + let sendSignalingMessageStub: sinon.SinonStub< + Parameters, + ReturnType + > + let consoleErrorStub: sinon.SinonStub< + Parameters, + ReturnType + > + + this.beforeAll(function () { + peerconnectionModels = Array.from(Array(100).keys()).map((n) => { + return { + uuid: n.toString(), + type: n % 2 === 0 ? 'webrtc' : 'local', + status: 'new', + deviceA: { + status: 'new', + url: `http://localhost/devices/${n}/a`, + }, + deviceB: { + status: 'new', + url: `http://localhost/devices/${n}/b`, + }, + signalingStarted: false, + } + }) + findOneOrFailStub = sinon.stub(peerconnectionRepository, 'findOneOrFail') + saveStub = sinon.stub(peerconnectionRepository, 'save') + sendSignalingMessageStub = sinon.stub(apiClient, 'sendSignalingMessage') + consoleErrorStub = sinon.stub(console, 'error') + }) + + this.afterEach(function () { + findOneOrFailStub.reset() + saveStub.reset() + sendSignalingMessageStub.reset() + consoleErrorStub.reset() + }) + + this.afterAll(function () { + findOneOrFailStub.restore() + saveStub.restore() + sendSignalingMessageStub.restore() + consoleErrorStub.restore() + }) + + function addPeerconnections() { + const rng = seedrandom('test') + for (let i = 0; i < 10 * peerconnectionModels.length; i++) { + const index = Math.floor(rng() * peerconnectionModels.length) + assert(peerconnectionModels[index]) + signalingQueue.addPeerconnection(peerconnectionModels[index]) + } + } + + function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)) + } + + function findDevice( + peerconnectionModel: PeerconnectionModel, + device: 'a' | 'b' + ) { + return sendSignalingMessageStub.args.find( + (args) => + args[0] === + `http://localhost/devices/${peerconnectionModel.uuid}/${device}` && + args[1].messageType === 'command' && + args[1].command === 'createPeerconnection' && + args[1].connectionType === peerconnectionModel.type && + args[1].connectionUrl === + peerconnectionUrlFromId(peerconnectionModel.uuid) && + JSON.stringify(args[1].services) === + JSON.stringify( + peerconnectionModel.deviceA.config?.services ?? [] + ) && + args[1].tiebreaker === (device === 'b') && + args[2] === peerconnectionUrlFromId(peerconnectionModel.uuid) + ) + } + + it('should correctly handle added peerconnections', async function () { + findOneOrFailStub.callsFake(async (options) => { + assert(typeof options.where === 'object') + assert(!Array.isArray(options.where)) + assert(typeof options.where.uuid === 'string') + return peerconnectionModels[parseInt(options.where.uuid)] + }) + saveStub.callsFake( + async ( + peerconnectionModel: PeerconnectionModel & { + signalingStarted?: boolean + } + ) => { + assert(peerconnectionModel.status === 'connecting') + assert(peerconnectionModel.signalingStarted === false) + peerconnectionModel.signalingStarted = true + return peerconnectionModel + } + ) + + addPeerconnections() + while (!signalingQueue.isEmpty()) { + await sleep(20) + } + + assert(saveStub.callCount === peerconnectionModels.length) + assert( + sendSignalingMessageStub.callCount === 2 * peerconnectionModels.length + ) + + for (const peerconnectionModel of peerconnectionModels) { + assert( + saveStub.args.find( + (args) => args[0].uuid === peerconnectionModel.uuid + ) + ) + assert(findDevice(peerconnectionModel, 'a')) + assert(findDevice(peerconnectionModel, 'b')) + } + }) + + it('should log errors of peerconnectionRepository.findOneOrFail', async function () { + const error = new Error('Test Error') + findOneOrFailStub.rejects(error) + signalingQueue.addPeerconnection(peerconnectionModels[0]) + while (!signalingQueue.isEmpty()) { + await sleep(20) + } + assert(findOneOrFailStub.calledOnce) + assert(consoleErrorStub.calledOnce) + assert(consoleErrorStub.calledWith(error)) + }) + + it('should log errors of peerconnectionRepository.save', async function () { + const error = new Error('Test Error') + findOneOrFailStub.resolves(peerconnectionModels[0]) + saveStub.rejects(error) + peerconnectionModels[0].status = 'new' + signalingQueue.addPeerconnection(peerconnectionModels[0]) + while (!signalingQueue.isEmpty()) { + await sleep(20) + } + assert(saveStub.calledOnce) + assert(consoleErrorStub.calledOnce) + assert(consoleErrorStub.calledWith(error)) + }) + + it('should log errors of first apiClient.sendSignalingMessage', async function () { + const error = new Error('Test Error') + findOneOrFailStub.resolves(peerconnectionModels[0]) + sendSignalingMessageStub.onFirstCall().rejects(error) + peerconnectionModels[0].status = 'new' + signalingQueue.addPeerconnection(peerconnectionModels[0]) + while (!signalingQueue.isEmpty()) { + await sleep(20) + } + assert(sendSignalingMessageStub.calledOnce) + assert(consoleErrorStub.calledOnce) + assert(consoleErrorStub.calledWith(error)) + }) + + it('should log errors of second apiClient.sendSignalingMessage', async function () { + const error = new Error('Test Error') + findOneOrFailStub.resolves(peerconnectionModels[0]) + sendSignalingMessageStub.onSecondCall().rejects(error) + peerconnectionModels[0].status = 'new' + signalingQueue.addPeerconnection(peerconnectionModels[0]) + while (!signalingQueue.isEmpty()) { + await sleep(20) + } + assert(sendSignalingMessageStub.callCount === 2) + assert(consoleErrorStub.calledOnce) + assert(consoleErrorStub.calledWith(error)) + }) + }) describe('startSignaling', function () {}) }) From d275483b9f7e333dab72113d72d0ece2fe991049 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 28 Mar 2023 22:59:34 +0200 Subject: [PATCH 20/33] Add post /devices operation tests --- .../repositories/device/concreteDevice.ts | 7 +- .../device/instantiableBrowserDevice.ts | 2 +- .../device/instantiableCloudDevice.ts | 2 +- .../device/src/operations/devices/post.ts | 4 +- .../device/concreteDevice.spec.ts | 8 +- .../device/instantiableBrowserDevice.spec.ts | 4 +- .../device/instantiableCloudDevice.spec.ts | 4 +- .../test/database/repositories/index.spec.ts | 2 +- .../test/operations/devices/post.spec.ts | 103 ++++++++++++++++++ 9 files changed, 122 insertions(+), 14 deletions(-) diff --git a/services/device/src/database/repositories/device/concreteDevice.ts b/services/device/src/database/repositories/device/concreteDevice.ts index 8a23989d..2fae1cab 100644 --- a/services/device/src/database/repositories/device/concreteDevice.ts +++ b/services/device/src/database/repositories/device/concreteDevice.ts @@ -22,6 +22,7 @@ export class ConcreteDeviceRepository extends AbstractRepository< async create(data?: ConcreteDevice<'request'>): Promise { const model = await super.create(data) model.type = 'device' + model.connected = false return model } @@ -39,9 +40,9 @@ export class ConcreteDeviceRepository extends AbstractRepository< ...(await DeviceOverviewRepository.format(model)), type: 'device', announcedAvailability: model.announcedAvailability ?? [], - connected: model.connected, - experiment: model.experiment, - services: model.services, + connected: model.connected ?? false, + experiment: model.experiment ?? undefined, + services: model.services ?? undefined, } } } diff --git a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts index 456b2fbb..a7776559 100644 --- a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts +++ b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts @@ -47,7 +47,7 @@ export class InstantiableBrowserDeviceRepository extends AbstractRepository< ...(await DeviceOverviewRepository.format(model)), type: 'edge instantiable', codeUrl: model.codeUrl, - services: model.services, + services: model.services ?? undefined, } } } diff --git a/services/device/src/database/repositories/device/instantiableCloudDevice.ts b/services/device/src/database/repositories/device/instantiableCloudDevice.ts index 5aed1f0a..bd61e174 100644 --- a/services/device/src/database/repositories/device/instantiableCloudDevice.ts +++ b/services/device/src/database/repositories/device/instantiableCloudDevice.ts @@ -47,7 +47,7 @@ export class InstantiableCloudDeviceRepository extends AbstractRepository< ...(await DeviceOverviewRepository.format(model)), type: 'cloud instantiable', instantiateUrl: model.instantiateUrl, - services: model.services, + services: model.services ?? undefined, } } } diff --git a/services/device/src/operations/devices/post.ts b/services/device/src/operations/devices/post.ts index f1d8c344..894e8da6 100644 --- a/services/device/src/operations/devices/post.ts +++ b/services/device/src/operations/devices/post.ts @@ -23,9 +23,7 @@ export const postDevices: postDevicesSignature = async (parameters, body, user) console.log( `registering changed-callback for device ${deviceModel.uuid} to '${parameters.changedUrl}'` ) - const changedCallbackURLs = changedCallbacks.get(deviceModel.uuid) ?? [] - changedCallbackURLs.push(parameters.changedUrl) - changedCallbacks.set(deviceModel.uuid, changedCallbackURLs) + changedCallbacks.set(deviceModel.uuid, [parameters.changedUrl]) } console.log(`postDevices succeeded`) diff --git a/services/device/test/database/repositories/device/concreteDevice.spec.ts b/services/device/test/database/repositories/device/concreteDevice.spec.ts index e4c1aac5..78b49d30 100644 --- a/services/device/test/database/repositories/device/concreteDevice.spec.ts +++ b/services/device/test/database/repositories/device/concreteDevice.spec.ts @@ -55,9 +55,11 @@ class ConcreteDeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< ): boolean { assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) // TODO: validate announcedAvailability - assert(data.connected === model.connected) - assert(data.experiment === model.experiment) - assert(JSON.stringify(data.services) === JSON.stringify(model.services)) + assert(data.connected === (model.connected ?? false)) + assert(data.experiment === (model.experiment ?? undefined)) + assert( + JSON.stringify(data.services) === JSON.stringify(model.services ?? undefined) + ) return true } diff --git a/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts b/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts index 8ee51f73..58a1e119 100644 --- a/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts +++ b/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts @@ -59,7 +59,9 @@ class InstantiableBrowserDeviceRepositoryTestSuite extends AbstractRepositoryTes ): boolean { assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) assert(data.codeUrl === model.codeUrl) - assert(JSON.stringify(data.services) === JSON.stringify(model.services)) + assert( + JSON.stringify(data.services) === JSON.stringify(model.services ?? undefined) + ) return true } diff --git a/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts b/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts index c386fdca..52820977 100644 --- a/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts +++ b/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts @@ -59,7 +59,9 @@ class InstantiableCloudDeviceRepositoryTestSuite extends AbstractRepositoryTestS ): boolean { assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) assert(data.instantiateUrl === model.instantiateUrl) - assert(JSON.stringify(data.services) === JSON.stringify(model.services)) + assert( + JSON.stringify(data.services) === JSON.stringify(model.services ?? undefined) + ) return true } diff --git a/services/device/test/database/repositories/index.spec.ts b/services/device/test/database/repositories/index.spec.ts index 83c5cec3..c02ecb1e 100644 --- a/services/device/test/database/repositories/index.spec.ts +++ b/services/device/test/database/repositories/index.spec.ts @@ -47,7 +47,7 @@ export default () => export async function initTestDatabase(): Promise { const dataSourceConfig: DataSourceOptions = { type: 'sqlite', - database: ':memory:', + database: 'test/db/test.db', synchronize: true, dropSchema: true, entities: [ diff --git a/services/device/test/operations/devices/post.spec.ts b/services/device/test/operations/devices/post.spec.ts index b10907aa..f618d0a2 100644 --- a/services/device/test/operations/devices/post.spec.ts +++ b/services/device/test/operations/devices/post.spec.ts @@ -1,8 +1,111 @@ +import { DeviceRepository } from '../../../src/database/repositories/device' +import { apiClient } from '../../../src/globals' +import { changedCallbacks } from '../../../src/methods/callbacks' +import { postDevices, UnauthorizedError } from '../../../src/operations/devices' +import { deviceNames } from '../../data/devices/index.spec' import { TestData } from '../../data/index.spec' +import { deviceRepositoryTestSuite } from '../../database/repositories/device.spec' +import { EntityData } from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' +import * as sinon from 'sinon' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('POST /devices', context) + let getDeviceStub: sinon.SinonStub< + Parameters, + ReturnType + > + + suite.beforeAll(function () { + getDeviceStub = sinon.stub(apiClient, 'getDevice') + }) + + suite.afterEach(function () { + getDeviceStub.reset() + }) + + suite.afterAll(function () { + getDeviceStub.restore() + }) + + async function createDevice( + device: EntityData, + changedUrl?: string + ) { + getDeviceStub.callsFake(async (url, _options) => { + for (const dn of deviceNames) { + if (testData.devices[dn].response.url === url) + return testData.devices[dn].response + } + return { + url: 'http://localhost/devices/undefined', + type: 'device', + name: 'undefined', + owner: 'http://localhost/devices/undefined', + } + }) + const result = await postDevices({ changedUrl }, device.request, { + JWT: { + username: 'testuser', + url: device.model.owner, + scopes: [], + }, + }) + assert(result.status === 201) + + assert( + deviceRepositoryTestSuite.compareFormatted(result.body, { + ...device.response, + url: result.body.url, + }) + ) + assert(changedCallbacks.get(device.model.uuid) === changedUrl) + } + + suite.addTest( + new Mocha.Test('should create a new device', async function () { + for (const deviceName of deviceNames) { + await createDevice(testData.devices[deviceName]) + } + }) + ) + + suite.addTest( + new Mocha.Test( + 'should create a new device and register a callback url', + async function () { + for (const deviceName of deviceNames) { + createDevice( + testData.devices[deviceName], + `http://localhost/callbacks/${deviceName}` + ) + } + } + ) + ) + + suite.addTest( + new Mocha.Test( + 'should throw an error if no UserData for JWT is provided', + async function () { + await assert.rejects( + async () => { + await postDevices( + {}, + testData.devices['concrete device'].request, + {} + ) + }, + (error) => { + assert(error instanceof UnauthorizedError) + assert(error.status === 401) + return true + } + ) + } + ) + ) return suite } From 8896cc2a19c0f9f53635faebab3a319683d7361c Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 28 Mar 2023 23:02:54 +0200 Subject: [PATCH 21/33] fix build script --- services/device/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/device/package.json b/services/device/package.json index 2160c26a..4b61162f 100644 --- a/services/device/package.json +++ b/services/device/package.json @@ -13,7 +13,7 @@ "openapi-bundle": "npx --yes @redocly/cli bundle ./api/openapi.yml --output dist/openapi.json", "watch-openapi": "npx --yes chokidar-cli 'api/**/*.yml' -c 'npm run openapi-bundle'", "watch-rapidoc": "npx --yes browser-sync start --server --startPath 'api/rapidoc.html' --files 'dist/openapi.json'", - "build": "npm-run-all build:*", + "build": "npm-run-all build:generate build:compile", "build:compile": "tsc --project tsconfig.build.json", "build:generate": "npm-run-all build:generate:*", "build:generate:code": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service -o src/generated", From 5151c62bfbee40ecc9883392b9b9c94b13899727 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Wed, 29 Mar 2023 18:23:51 +0200 Subject: [PATCH 22/33] WIP: Add further testData and operation tests --- .../repositories/device/deviceGroup.ts | 5 +- .../deviceGroups/device_group_nested.spec.ts | 42 +++ .../data/devices/deviceGroups/index.spec.ts | 4 +- services/device/test/data/index.spec.ts | 16 +- .../test/database/repositories/device.spec.ts | 12 +- .../device/concreteDevice.spec.ts | 5 +- .../repositories/device/deviceGroup.spec.ts | 28 +- .../device/instantiableBrowserDevice.spec.ts | 2 +- .../device/instantiableCloudDevice.spec.ts | 2 +- .../test/database/repositories/index.spec.ts | 2 +- .../operations/devices/device/delete.spec.ts | 64 +++++ .../operations/devices/device/get.spec.ts | 95 +++++++ .../operations/devices/device/patch.spec.ts | 239 ++++++++++++++++++ .../operations/devices/device/post.spec.ts | 24 ++ .../test/operations/devices/get.spec.ts | 2 +- .../test/operations/devices/index.spec.ts | 3 +- .../test/operations/devices/post.spec.ts | 3 +- .../operations/peerconnections/get.spec.ts | 2 +- 18 files changed, 533 insertions(+), 17 deletions(-) create mode 100644 services/device/test/data/devices/deviceGroups/device_group_nested.spec.ts diff --git a/services/device/src/database/repositories/device/deviceGroup.ts b/services/device/src/database/repositories/device/deviceGroup.ts index 28968a88..c1e9bcb4 100644 --- a/services/device/src/database/repositories/device/deviceGroup.ts +++ b/services/device/src/database/repositories/device/deviceGroup.ts @@ -52,7 +52,10 @@ export class DeviceGroupRepository extends AbstractRepository< return { ...(await DeviceOverviewRepository.format(model)), type: 'group', - devices: devices, + devices: devices.filter( + (value, index, array) => + array.findIndex((device) => device.url === value.url) === index + ), } } diff --git a/services/device/test/data/devices/deviceGroups/device_group_nested.spec.ts b/services/device/test/data/devices/deviceGroups/device_group_nested.spec.ts new file mode 100644 index 00000000..8a674e16 --- /dev/null +++ b/services/device/test/data/devices/deviceGroups/device_group_nested.spec.ts @@ -0,0 +1,42 @@ +import { DeviceGroupRepository } from '../../../../src/database/repositories/device/deviceGroup' +import { deviceUrlFromId } from '../../../../src/methods/urlFromId' +import { concreteDeviceData } from '../concreteDevices/index.spec' +import device_group from './device_group.spec' +import { EntityData } from '@crosslab/service-common' + +const uuid = 'e78b289a-44c5-452f-8c7b-d983714d5645' +const type = 'group' +const name = 'Nested Device Group Example' +const description = 'An example for a nested device group' +const owner = 'http://localhost/users/superadmin' +const devices = [ + { url: concreteDeviceData['concrete device'].response.url }, + { url: device_group.response.url }, +] + +const device_group_nested: EntityData = { + request: { + type, + name, + description, + devices, + }, + model: { + uuid, + type, + name, + description, + devices, + owner, + }, + response: { + url: deviceUrlFromId(uuid), + type, + name, + description, + devices: [concreteDeviceData['concrete device'].response, device_group.response], + owner, + }, +} + +export default device_group_nested diff --git a/services/device/test/data/devices/deviceGroups/index.spec.ts b/services/device/test/data/devices/deviceGroups/index.spec.ts index ab7be5fa..d3896af7 100644 --- a/services/device/test/data/devices/deviceGroups/index.spec.ts +++ b/services/device/test/data/devices/deviceGroups/index.spec.ts @@ -1,11 +1,13 @@ import { DeviceGroupRepository } from '../../../../src/database/repositories/device/deviceGroup' import device_group from './device_group.spec' +import device_group_nested from './device_group_nested.spec' import { EntityData } from '@crosslab/service-common' -export const deviceGroupNames = ['device group'] as const +export const deviceGroupNames = ['device group', 'nested device group'] as const export type DeviceGroupName = (typeof deviceGroupNames)[number] export type DeviceGroupData = Record> export const deviceGroupData: DeviceGroupData = { 'device group': { ...device_group }, + 'nested device group': { ...device_group_nested }, } diff --git a/services/device/test/data/index.spec.ts b/services/device/test/data/index.spec.ts index 101026b0..6b1121d2 100644 --- a/services/device/test/data/index.spec.ts +++ b/services/device/test/data/index.spec.ts @@ -4,6 +4,7 @@ import { DeviceGroupRepository } from '../../src/database/repositories/device/de import { InstantiableBrowserDeviceRepository } from '../../src/database/repositories/device/instantiableBrowserDevice' import { InstantiableCloudDeviceRepository } from '../../src/database/repositories/device/instantiableCloudDevice' import { PeerconnectionRepository } from '../../src/database/repositories/peerconnection' +import { UserData, UserType } from '../../src/generated/types' import { concreteDeviceData, ConcreteDeviceName, @@ -38,7 +39,16 @@ export type TestData = GenericTestData< ['devices', DeviceName, DeviceRepository], ['peerconnections', PeerconnectionName, PeerconnectionRepository] ] -> +> & { + user: UserType + userData: UserData<'JWT'> +} + +const testUser: UserType = { + url: 'http://localhost/users/testuser', + username: 'testuser', + scopes: [], +} export function prepareTestData(): TestData { return { @@ -48,5 +58,9 @@ export function prepareTestData(): TestData { 'instantiable cloud devices': instantiableCloudDeviceData, 'devices': deviceData, 'peerconnections': peerconnectionData, + 'user': testUser, + 'userData': { + JWT: testUser, + }, } } diff --git a/services/device/test/database/repositories/device.spec.ts b/services/device/test/database/repositories/device.spec.ts index 26f356d7..ae6fb43b 100644 --- a/services/device/test/database/repositories/device.spec.ts +++ b/services/device/test/database/repositories/device.spec.ts @@ -111,7 +111,11 @@ class DeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< } } - validateFormat(model: DeviceModel, data: Device<'response'>): boolean { + validateFormat( + model: DeviceModel, + data: Device<'response'>, + options?: { flatten?: boolean } + ): boolean { switch (model.type) { case 'cloud instantiable': assert(data?.type === model.type) @@ -130,7 +134,11 @@ class DeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< ) case 'group': assert(data?.type === model.type) - return deviceGroupRepositoryTestSuite.validateFormat(model, data) + return deviceGroupRepositoryTestSuite.validateFormat( + model, + data, + options?.flatten + ) } } diff --git a/services/device/test/database/repositories/device/concreteDevice.spec.ts b/services/device/test/database/repositories/device/concreteDevice.spec.ts index 78b49d30..41e63a3f 100644 --- a/services/device/test/database/repositories/device/concreteDevice.spec.ts +++ b/services/device/test/database/repositories/device/concreteDevice.spec.ts @@ -54,12 +54,15 @@ class ConcreteDeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< data: ConcreteDevice<'response'> ): boolean { assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) - // TODO: validate announcedAvailability assert(data.connected === (model.connected ?? false)) assert(data.experiment === (model.experiment ?? undefined)) assert( JSON.stringify(data.services) === JSON.stringify(model.services ?? undefined) ) + assert( + JSON.stringify(model.announcedAvailability) === + JSON.stringify(data.announcedAvailability) + ) return true } diff --git a/services/device/test/database/repositories/device/deviceGroup.spec.ts b/services/device/test/database/repositories/device/deviceGroup.spec.ts index f3bdc7ac..0e3a0770 100644 --- a/services/device/test/database/repositories/device/deviceGroup.spec.ts +++ b/services/device/test/database/repositories/device/deviceGroup.spec.ts @@ -4,8 +4,10 @@ import { deviceGroupRepository, DeviceGroupRepository, } from '../../../../src/database/repositories/device/deviceGroup' -import { DeviceGroup, DeviceGroupUpdate } from '../../../../src/generated/types' +import { Device, DeviceGroup, DeviceGroupUpdate } from '../../../../src/generated/types' import { DeviceGroupName } from '../../../data/devices/deviceGroups/index.spec' +import { prepareTestData } from '../../../data/index.spec' +import { deviceRepositoryTestSuite } from '../device.spec' import { initTestDatabase } from '../index.spec' import { DeviceOverviewRepositoryTestSuite } from './deviceOverview.spec' import { AbstractRepositoryTestSuite } from '@crosslab/service-common' @@ -16,8 +18,9 @@ class DeviceGroupRepositoryTestSuite extends AbstractRepositoryTestSuite< DeviceGroupName, DeviceGroupRepository > { - protected name = 'concrete devices' as const + protected name = 'device groups' as const protected repository = deviceGroupRepository + protected testData = prepareTestData() protected getEntityData = async () => (await initTestDatabase())['device groups'] protected RepositoryClass = DeviceGroupRepository @@ -45,9 +48,26 @@ class DeviceGroupRepositoryTestSuite extends AbstractRepositoryTestSuite< return true } - validateFormat(model: DeviceGroupModel, data: DeviceGroup<'response'>): boolean { + validateFormat( + model: DeviceGroupModel, + data: DeviceGroup<'response'>, + flatten?: boolean + ): boolean { assert(DeviceOverviewRepositoryTestSuite.validateFormat(model, data)) - // TODO: validate devices + + for (const device of data.devices ?? []) { + if (flatten) assert(device.type !== 'group') + const searchedDeviceModel = Object.entries(this.testData.devices).find( + (entry) => entry[1].response.url === device.url + )?.[1].model + assert(searchedDeviceModel) + assert( + deviceRepositoryTestSuite.validateFormat( + searchedDeviceModel, + device as Device + ) + ) + } return true } diff --git a/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts b/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts index 58a1e119..63b85e07 100644 --- a/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts +++ b/services/device/test/database/repositories/device/instantiableBrowserDevice.spec.ts @@ -19,7 +19,7 @@ class InstantiableBrowserDeviceRepositoryTestSuite extends AbstractRepositoryTes InstantiableBrowserDeviceName, InstantiableBrowserDeviceRepository > { - protected name = 'concrete devices' as const + protected name = 'instantiable browser devices' as const protected repository = instantiableBrowserDeviceRepository protected getEntityData = async () => (await initTestDatabase())['instantiable browser devices'] diff --git a/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts b/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts index 52820977..787f4efc 100644 --- a/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts +++ b/services/device/test/database/repositories/device/instantiableCloudDevice.spec.ts @@ -19,7 +19,7 @@ class InstantiableCloudDeviceRepositoryTestSuite extends AbstractRepositoryTestS InstantiableCloudDeviceName, InstantiableCloudDeviceRepository > { - protected name = 'concrete devices' as const + protected name = 'instantiable cloud devices' as const protected repository = instantiableCloudDeviceRepository protected getEntityData = async () => (await initTestDatabase())['instantiable cloud devices'] diff --git a/services/device/test/database/repositories/index.spec.ts b/services/device/test/database/repositories/index.spec.ts index c02ecb1e..83c5cec3 100644 --- a/services/device/test/database/repositories/index.spec.ts +++ b/services/device/test/database/repositories/index.spec.ts @@ -47,7 +47,7 @@ export default () => export async function initTestDatabase(): Promise { const dataSourceConfig: DataSourceOptions = { type: 'sqlite', - database: 'test/db/test.db', + database: ':memory:', synchronize: true, dropSchema: true, entities: [ diff --git a/services/device/test/operations/devices/device/delete.spec.ts b/services/device/test/operations/devices/device/delete.spec.ts index 024dcd4e..71fbfc24 100644 --- a/services/device/test/operations/devices/device/delete.spec.ts +++ b/services/device/test/operations/devices/device/delete.spec.ts @@ -1,8 +1,72 @@ +import { deviceRepository } from '../../../../src/database/repositories/device' +import { deleteDevicesByDeviceId } from '../../../../src/operations/devices' +import { deviceNames } from '../../../data/devices/index.spec' import { TestData } from '../../../data/index.spec' +import { MissingEntityError } from '@crosslab/service-common' +import assert, { fail } from 'assert' import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('DELETE /devices/{device_id}', context) + suite.addTest( + new Mocha.Test('should delete the device', async function () { + for (const deviceName of deviceNames) { + const deviceModel = testData.devices[deviceName].model + const result = await deleteDevicesByDeviceId( + { device_id: deviceModel.uuid }, + testData.userData + ) + assert(result.status === 204) + assert( + (await deviceRepository.findOne({ + where: { + uuid: deviceModel.uuid, + }, + })) === null + ) + } + }) + ) + + suite.addTest( + new Mocha.Test( + 'should throw a MissingEntityError if device is not found', + async function () { + await assert.rejects( + async () => { + await deleteDevicesByDeviceId( + { device_id: 'non-existent' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert(error.status === 404) + return true + } + ) + } + ) + ) + + suite.addTest( + new Mocha.Test( + 'should throw an error if user is not the owner of the device', + async function () { + fail() + } + ) + ) + + suite.addTest( + new Mocha.Test( + 'superadmin/admin should be able to delete the device', + async function () { + fail() + } + ) + ) + return suite } diff --git a/services/device/test/operations/devices/device/get.spec.ts b/services/device/test/operations/devices/device/get.spec.ts index d4feba07..2b40107a 100644 --- a/services/device/test/operations/devices/device/get.spec.ts +++ b/services/device/test/operations/devices/device/get.spec.ts @@ -1,8 +1,103 @@ +import { apiClient } from '../../../../src/globals' +import { getDevicesByDeviceId } from '../../../../src/operations/devices' +import { deviceGroupNames } from '../../../data/devices/deviceGroups/index.spec' +import { deviceNames } from '../../../data/devices/index.spec' import { TestData } from '../../../data/index.spec' +import { deviceRepositoryTestSuite } from '../../../database/repositories/device.spec' +import { MissingEntityError } from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' +import * as sinon from 'sinon' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('GET /devices/{device_id}', context) + let getDeviceStub: sinon.SinonStub< + Parameters, + ReturnType + > + + suite.beforeAll(function () { + getDeviceStub = sinon.stub(apiClient, 'getDevice') + getDeviceStub.callsFake(async (url, options) => { + console.debug(url.split('/').at(-1) ?? 'non-existent') + const result = await getDevicesByDeviceId( + { + device_id: url.split('/').at(-1) ?? 'non-existent', + flat_group: options?.flat_group, + }, + testData.userData + ) + assert(result.status === 200) + console.debug(result.body.name) + return result.body + }) + }) + + suite.afterAll(function () { + getDeviceStub.restore() + }) + + suite.addTest( + new Mocha.Test('should return the formatted device', async function () { + for (const deviceName of deviceNames) { + const device = testData.devices[deviceName] + const result = await getDevicesByDeviceId( + { device_id: device.model.uuid }, + testData.userData + ) + + assert(result.status === 200) + assert( + deviceRepositoryTestSuite.validateFormat(device.model, result.body) + ) + } + }) + ) + + suite.addTest( + new Mocha.Test( + 'should return the flattened formatted device group', + async function () { + for (const deviceGroupName of deviceGroupNames) { + const deviceGroup = testData['device groups'][deviceGroupName] + const result = await getDevicesByDeviceId( + { device_id: deviceGroup.model.uuid, flat_group: true }, + testData.userData + ) + + assert(result.status === 200) + assert( + deviceRepositoryTestSuite.validateFormat( + deviceGroup.model, + result.body, + { flatten: true } + ) + ) + } + } + ) + ) + + suite.addTest( + new Mocha.Test( + 'should throw a MissingEntityError if device is not found', + async function () { + await assert.rejects( + async () => { + await getDevicesByDeviceId( + { device_id: 'non-existent' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert(error.status === 404) + return true + } + ) + } + ) + ) return suite } diff --git a/services/device/test/operations/devices/device/patch.spec.ts b/services/device/test/operations/devices/device/patch.spec.ts index df50cbb9..0d156162 100644 --- a/services/device/test/operations/devices/device/patch.spec.ts +++ b/services/device/test/operations/devices/device/patch.spec.ts @@ -1,8 +1,247 @@ +import { deviceRepository } from '../../../../src/database/repositories/device' +import { + ConcreteDeviceUpdate, + DeviceGroupUpdate, + DeviceUpdate, + InstantiableBrowserDeviceUpdate, + InstantiableCloudDeviceUpdate, + ServiceDescription, +} from '../../../../src/generated/types' +import { changedCallbacks } from '../../../../src/methods/callbacks' +import { patchDevicesByDeviceId } from '../../../../src/operations/devices' +import { concreteDeviceNames } from '../../../data/devices/concreteDevices/index.spec' +import { deviceGroupNames } from '../../../data/devices/deviceGroups/index.spec' +import { deviceNames } from '../../../data/devices/index.spec' +import { instantiableBrowserDeviceNames } from '../../../data/devices/instantiableBrowserDevices/index.spec' +import { instantiableCloudDeviceNames } from '../../../data/devices/instantiableCloudDevices/index.spec' import { TestData } from '../../../data/index.spec' +import { deviceRepositoryTestSuite } from '../../../database/repositories/device.spec' +import { InvalidValueError, MissingEntityError } from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('PATCH /devices/{device_id}', context) + const updatedName = 'new name' + const updatedDescription = 'new description' + const updatedServices: ServiceDescription[] = [ + { + serviceDirection: 'consumer', + serviceId: 'new consumer service', + serviceType: 'new consumer service', + }, + { + serviceDirection: 'producer', + serviceId: 'new producer service', + serviceType: 'new producer service', + }, + { + serviceDirection: 'prosumer', + serviceId: 'new prosumer service', + serviceType: 'new prosumer service', + }, + ] + + const concreteDeviceBody: ConcreteDeviceUpdate = { + type: 'device', + description: updatedDescription, + experiment: 'http://localhost/experiments/new', + name: updatedName, + services: updatedServices, + } + + const deviceGroupBody: DeviceGroupUpdate = { + type: 'group', + description: updatedDescription, + devices: [ + { url: 'http://localhost/devices/new1' }, + { url: 'http://localhost/devices/new2' }, + { url: 'http://localhost/devices/new3' }, + ], + name: updatedName, + } + + const instantiableBrowserDeviceBody: InstantiableBrowserDeviceUpdate = { + type: 'edge instantiable', + codeUrl: 'http://localhost/code/new', + description: updatedDescription, + name: updatedName, + services: updatedServices, + } + + const instantiableCloudDeviceBody: InstantiableCloudDeviceUpdate = { + type: 'cloud instantiable', + description: updatedDescription, + instantiateUrl: 'http://localhost/instantiate/new', + name: updatedName, + services: updatedServices, + } + + function getDeviceData( + type: 'device' | 'group' | 'edge instantiable' | 'cloud instantiable' + ): { + body: DeviceUpdate + names: + | typeof instantiableBrowserDeviceNames + | typeof instantiableCloudDeviceNames + | typeof concreteDeviceNames + | typeof deviceGroupNames + } { + switch (type) { + case 'cloud instantiable': + return { + body: instantiableCloudDeviceBody, + names: instantiableCloudDeviceNames, + } + case 'device': + return { + body: concreteDeviceBody, + names: concreteDeviceNames, + } + case 'edge instantiable': + return { + body: instantiableBrowserDeviceBody, + names: instantiableBrowserDeviceNames, + } + case 'group': + return { + body: deviceGroupBody, + names: deviceGroupNames, + } + } + } + + function buildDeviceSuite( + type: 'device' | 'group' | 'edge instantiable' | 'cloud instantiable' + ): Mocha.Suite { + return new Mocha.Suite(`device type '${type}'`) + .addTest( + new Mocha.Test( + `should update a device of type '${type}'`, + async function () { + const deviceData = getDeviceData(type) + for (const deviceName of deviceData.names) { + const device = testData['devices'][deviceName] + const result = await patchDevicesByDeviceId( + { device_id: device.model.uuid }, + deviceData.body, + testData.userData + ) + + assert(result.status === 200) + const updatedDeviceModel = + await deviceRepository.findOneOrFail({ + where: { + uuid: device.model.uuid, + }, + }) + assert( + deviceRepositoryTestSuite.validateWrite( + updatedDeviceModel, + deviceData.body + ) + ) + assert(changedCallbacks.get(device.model.uuid) === undefined) + } + } + ) + ) + .addTest( + new Mocha.Test( + `should throw an error if the type of the update is not '${type}'`, + async function () { + const deviceData = getDeviceData(type) + for (const deviceName of deviceData.names) { + const device = testData['devices'][deviceName] + for (const deviceType of [ + 'device', + 'group', + 'edge instantiable', + 'cloud instantiable', + ] as const) { + if (deviceType === type) continue + await assert.rejects( + async () => { + await patchDevicesByDeviceId( + { device_id: device.model.uuid }, + { type: deviceType }, + testData.userData + ) + }, + (error) => { + assert(error instanceof InvalidValueError) + assert(error.status === 400) + return true + } + ) + } + } + } + ) + ) + } + + suite.afterEach(function () { + changedCallbacks.clear() + }) + + suite.addSuite(buildDeviceSuite('cloud instantiable')) + suite.addSuite(buildDeviceSuite('device')) + suite.addSuite(buildDeviceSuite('edge instantiable')) + suite.addSuite(buildDeviceSuite('group')) + + suite.addTest( + new Mocha.Test( + 'should throw a MissingEntityError if device is not found', + async function () { + await assert.rejects( + async () => { + await patchDevicesByDeviceId( + { device_id: 'non-existent' }, + { type: 'device' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert(error.status === 404) + return true + } + ) + } + ) + ) + + suite.addTest( + new Mocha.Test( + 'should register a device-changed callback url for the device if provided', + async function () { + for (const deviceName of deviceNames) { + const device = testData.devices[deviceName] + const changedUrl = 'http://localhost/callbacks' + + const result = await patchDevicesByDeviceId( + { device_id: device.model.uuid, changedUrl }, + undefined, + testData.userData + ) + + assert(result.status === 200) + assert( + deviceRepositoryTestSuite.validateWrite( + device.model, + device.request + ) + ) + const changedCallbackUrls = changedCallbacks.get(device.model.uuid) + assert(changedCallbackUrls) + assert(changedCallbackUrls.length === 1) + assert(changedCallbackUrls[0] === changedUrl) + } + } + ) + ) + return suite } diff --git a/services/device/test/operations/devices/device/post.spec.ts b/services/device/test/operations/devices/device/post.spec.ts index 9fc26b84..b03aa9be 100644 --- a/services/device/test/operations/devices/device/post.spec.ts +++ b/services/device/test/operations/devices/device/post.spec.ts @@ -1,8 +1,32 @@ +import { postDevicesByDeviceId } from '../../../../src/operations/devices' import { TestData } from '../../../data/index.spec' +import { MissingEntityError } from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('POST /devices/{device_id}', context) + suite.addTest( + new Mocha.Test( + 'should throw a MissingEntityError if device is not found', + async function () { + await assert.rejects( + async () => { + await postDevicesByDeviceId( + { device_id: 'non-existent' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert(error.status === 404) + return true + } + ) + } + ) + ) + return suite } diff --git a/services/device/test/operations/devices/get.spec.ts b/services/device/test/operations/devices/get.spec.ts index 9e2adc86..f44e7f82 100644 --- a/services/device/test/operations/devices/get.spec.ts +++ b/services/device/test/operations/devices/get.spec.ts @@ -10,7 +10,7 @@ export default function (context: Mocha.Context, testData: TestData) { suite.addTest( new Mocha.Test('should get all devices', async function () { - const result = await getDevices({}) + const result = await getDevices(testData.userData) assert(result.status === 200) for (const deviceName of deviceNames) { diff --git a/services/device/test/operations/devices/index.spec.ts b/services/device/test/operations/devices/index.spec.ts index 1ac2862c..ec94cb6b 100644 --- a/services/device/test/operations/devices/index.spec.ts +++ b/services/device/test/operations/devices/index.spec.ts @@ -1,4 +1,5 @@ +import deviceTests from './device/index.spec' import getSpec from './get.spec' import postSpec from './post.spec' -export default [getSpec, postSpec] +export default [getSpec, postSpec, ...deviceTests] diff --git a/services/device/test/operations/devices/post.spec.ts b/services/device/test/operations/devices/post.spec.ts index f618d0a2..fa974c0b 100644 --- a/services/device/test/operations/devices/post.spec.ts +++ b/services/device/test/operations/devices/post.spec.ts @@ -27,6 +27,7 @@ export default function (context: Mocha.Context, testData: TestData) { suite.afterAll(function () { getDeviceStub.restore() + console.debug('afterAll executed') }) async function createDevice( @@ -94,7 +95,7 @@ export default function (context: Mocha.Context, testData: TestData) { await postDevices( {}, testData.devices['concrete device'].request, - {} + testData.userData ) }, (error) => { diff --git a/services/device/test/operations/peerconnections/get.spec.ts b/services/device/test/operations/peerconnections/get.spec.ts index 2da5db25..7531c4c6 100644 --- a/services/device/test/operations/peerconnections/get.spec.ts +++ b/services/device/test/operations/peerconnections/get.spec.ts @@ -10,7 +10,7 @@ export default function (context: Mocha.Context, testData: TestData) { suite.addTest( new Mocha.Test('should get all peerconnections', async function () { - const result = await getPeerconnections({}) + const result = await getPeerconnections(testData.userData) assert(result.status === 200) for (const peerconnectionName of peerconnectionNames) { From 20c685d408cf9038b7d944eaad073a40ca23dd68 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Fri, 31 Mar 2023 09:52:41 +0200 Subject: [PATCH 23/33] Update securityRequirement handling and UserData type --- .../templates/service-test/routes.spec.ts.njk | 6 +++++- .../templates/service/routes.ts.njk | 13 ++++++++++--- .../templates/service/types.ts.njk | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/helper/crosslab-typescript-addon/templates/service-test/routes.spec.ts.njk b/helper/crosslab-typescript-addon/templates/service-test/routes.spec.ts.njk index 3901a336..b2e11440 100644 --- a/helper/crosslab-typescript-addon/templates/service-test/routes.spec.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service-test/routes.spec.ts.njk @@ -73,7 +73,11 @@ export default () => describe('Route Tests', function () { validateOutputStub = undefined operationStub = undefined {%- for securityScheme in securitySchemes %} - {{ securityScheme }}SecurityStub.reset() + {{ securityScheme }}SecurityStub.resolves({ + url: "http://localhost/users/{{ securityScheme }}user", + username: "{{ securityScheme }}user", + scopes: [] + }) {%- endfor %} errorHandlerStub.callsFake(defaultErrorHandler) diff --git a/helper/crosslab-typescript-addon/templates/service/routes.ts.njk b/helper/crosslab-typescript-addon/templates/service/routes.ts.njk index 9bcb476b..e2868aaa 100644 --- a/helper/crosslab-typescript-addon/templates/service/routes.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service/routes.ts.njk @@ -41,6 +41,8 @@ import express from "express" import operations from "../operations" import { + UserType, + isUserType, {{ typeDependencies | unique | join(",\n\t") }} } from "./types" @@ -63,11 +65,16 @@ export default function routes( [k in T]: string[] } ): Promise> { - let userData: UserData = {} + const userDataEntries: [T, UserType][] = [] for (const method in securityRequirement) { - userData[method] = await options.security[method](request, securityRequirement[method]) + const user = await options.security[method]( + request, + securityRequirement[method] + ) + if (!isUserType(user)) throw new Error(`User resolved by method ${method} is not of type 'UserType'`) + userDataEntries.push([method, user]) } - return userData + return Object.fromEntries(userDataEntries) as UserData; } {%- for operation in operations %} diff --git a/helper/crosslab-typescript-addon/templates/service/types.ts.njk b/helper/crosslab-typescript-addon/templates/service/types.ts.njk index 0de586d7..b077cfd0 100644 --- a/helper/crosslab-typescript-addon/templates/service/types.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service/types.ts.njk @@ -32,7 +32,7 @@ export type TypedRequest = Request export type initServiceOptions = { {%- if securitySchemes | length > 0 %} security: { - [k in T]: (req: TypedRequest, scopes: string[]) => Promise | UserType | undefined + [k in T]: (req: TypedRequest, scopes: string[]) => Promise | UserType } {%- endif %} errorHandler?: ErrorRequestHandler @@ -40,7 +40,7 @@ export type initServiceOptions = { } export type UserData = { - [k in T]?: UserType + [k in T]: UserType } export interface ResponseData { From e18978550d25bb8741d78fc83bebd23ef015cf81 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 18 Apr 2023 11:25:51 +0200 Subject: [PATCH 24/33] Update openapi, edit models, fix device repository, add tests - make property devices required on device groups - make properties connected, announcedAvailability, availability- Rules and services required on ConcreteDeviceModel - adapt device repository to reflect changes to models and api - add test for POST /devices/{device_id} (WIP) --- .../api/schemas/devices/device_group.yml | 2 + services/device/dist/openapi.json | 5 +- services/device/package-lock.json | 478 +++--------------- services/device/src/database/dataSource.ts | 8 - services/device/src/database/model.ts | 10 +- .../src/database/repositories/device.ts | 142 +++++- .../repositories/device/concreteDevice.ts | 15 +- .../repositories/device/deviceGroup.ts | 14 +- .../repositories/device/deviceOverview.ts | 21 +- .../device/instantiableBrowserDevice.ts | 6 +- .../device/instantiableCloudDevice.ts | 6 +- .../src/operations/devices/device/post.ts | 14 - services/device/src/operations/devices/get.ts | 5 +- .../device/src/operations/devices/post.ts | 6 +- .../src/operations/peerconnections/post.ts | 4 +- .../concreteDevices/concrete_device.spec.ts | 4 + .../test/database/repositories/device.spec.ts | 5 + .../device/test/methods/callbacks.spec.ts | 4 + .../operations/devices/device/delete.spec.ts | 10 +- .../operations/devices/device/get.spec.ts | 2 - .../operations/devices/device/post.spec.ts | 126 ++++- .../test/operations/devices/post.spec.ts | 42 +- services/openapi/dist/openapi.json | 294 +++-------- 23 files changed, 479 insertions(+), 744 deletions(-) diff --git a/services/device/api/schemas/devices/device_group.yml b/services/device/api/schemas/devices/device_group.yml index 1c362016..77dc88cf 100644 --- a/services/device/api/schemas/devices/device_group.yml +++ b/services/device/api/schemas/devices/device_group.yml @@ -10,4 +10,6 @@ allOf: type: array items: $ref: ./references/device_reference.yml + required: + - devices x-typeguard: true \ No newline at end of file diff --git a/services/device/dist/openapi.json b/services/device/dist/openapi.json index f9146fb7..788a00ba 100644 --- a/services/device/dist/openapi.json +++ b/services/device/dist/openapi.json @@ -278,7 +278,10 @@ "$ref": "#/components/schemas/device_reference" } } - } + }, + "required": [ + "devices" + ] } ], "x-typeguard": true diff --git a/services/device/package-lock.json b/services/device/package-lock.json index 7bf03f01..0355796a 100644 --- a/services/device/package-lock.json +++ b/services/device/package-lock.json @@ -59,6 +59,7 @@ } }, "../../clients/api/js": { + "name": "@cross-lab-project/api-client", "license": "ISC", "dependencies": { "ajv-formats": "^2.1.1", @@ -78,6 +79,7 @@ } }, "../../helper/crosslab-typescript-addon": { + "name": "@cross-lab-project/codegen-typescript-addon", "dev": true, "license": "UNLICENSED", "devDependencies": { @@ -105,6 +107,7 @@ } }, "../../helper/openapi-codegeneration": { + "name": "@cross-lab-project/openapi-codegen", "dev": true, "license": "UNLICENSED", "dependencies": { @@ -113,6 +116,7 @@ "ajv-formats": "^2.1.1", "commander": "^9.4.1", "deterministic-json-schema-faker": "^0.5.0-rcv.46", + "json-schema-merge-allof": "^0.8.1", "json-schema-to-typescript": "^10.1.5", "nunjucks": "^3.2.3", "prettier": "^2.6.2", @@ -138,16 +142,20 @@ } }, "../common": { + "name": "@crosslab/service-common", "license": "UNLICENSED", "dependencies": { "jose": "^4.11.1" }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "eslint": "^8.34.0", + "mocha": "^10.2.0", + "typeorm": "^0.3.6", "typescript": "^4.9.4" } }, @@ -1435,24 +1443,12 @@ "dev": true, "optional": true }, - "node_modules/@types/lodash": { - "version": "4.14.191", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", - "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", - "dev": true - }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, "node_modules/@types/mocha": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", @@ -2350,27 +2346,6 @@ "node": ">=8" } }, - "node_modules/brfs": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/brfs/-/brfs-1.6.1.tgz", - "integrity": "sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ==", - "dev": true, - "dependencies": { - "quote-stream": "^1.0.1", - "resolve": "^1.1.5", - "static-module": "^2.2.0", - "through2": "^2.0.0" - }, - "bin": { - "brfs": "bin/cmd.js" - } - }, - "node_modules/browser-or-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-1.3.0.tgz", - "integrity": "sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==", - "dev": true - }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -2428,6 +2403,12 @@ "ieee754": "^1.2.1" } }, + "node_modules/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 + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2510,6 +2491,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2763,12 +2750,6 @@ "node": ">=6" } }, - "node_modules/collection-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", - "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", - "dev": true - }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -2804,15 +2785,6 @@ "node": ">= 0.8" } }, - "node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -3020,19 +2992,6 @@ "node": ">=8" } }, - "node_modules/deterministic-json-schema-faker": { - "version": "0.5.0-rcv.46", - "resolved": "https://registry.npmjs.org/deterministic-json-schema-faker/-/deterministic-json-schema-faker-0.5.0-rcv.46.tgz", - "integrity": "sha512-pp7iiuue97ysVTMLXyLofpDembEepoGbdv79ie2Mdhqj4dtVQFpI9c6ecxjUiDFDBxScqWpPvVpWX88PxMPZGA==", - "dev": true, - "dependencies": { - "json-schema-ref-parser": "^6.1.0", - "jsonpath-plus": "^5.1.0" - }, - "bin": { - "jsf": "bin/gen.cjs" - } - }, "node_modules/dezalgo": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", @@ -3093,15 +3052,6 @@ "node": ">=4" } }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3287,60 +3237,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es5-ext": { - "version": "0.10.62", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", - "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -3644,6 +3546,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/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, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -4153,18 +4068,6 @@ "node": ">=8.0.0" } }, - "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -4822,12 +4725,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -4856,15 +4753,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -4932,12 +4820,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true - }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -4979,26 +4861,6 @@ "node": ">=0.10.0" } }, - "node_modules/isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==", - "dev": true, - "dependencies": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" - } - }, - "node_modules/isomorphic-fetch/node_modules/node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "dev": true, - "dependencies": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", @@ -5174,6 +5036,19 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, + "node_modules/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, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5217,78 +5092,6 @@ "ono": "^4.0.11" } }, - "node_modules/json-schema-to-typescript": { - "version": "10.1.5", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-10.1.5.tgz", - "integrity": "sha512-X8bNNksfCQo6LhEuqNxmZr4eZpPjXZajmimciuk8eWXzZlif9Brq7WuMGD/SOhBKcRKP2SGVDNZbC28WQqx9Rg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.6", - "@types/lodash": "^4.14.168", - "@types/prettier": "^2.1.5", - "cli-color": "^2.0.0", - "get-stdin": "^8.0.0", - "glob": "^7.1.6", - "glob-promise": "^3.4.0", - "is-glob": "^4.0.1", - "json-schema-ref-parser": "^9.0.6", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.20", - "minimist": "^1.2.5", - "mkdirp": "^1.0.4", - "mz": "^2.7.0", - "prettier": "^2.2.0" - }, - "bin": { - "json2ts": "dist/src/cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/json-schema-to-typescript/node_modules/@apidevtools/json-schema-ref-parser": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", - "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", - "dev": true, - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.6", - "call-me-maybe": "^1.0.1", - "js-yaml": "^4.1.0" - } - }, - "node_modules/json-schema-to-typescript/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/json-schema-to-typescript/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-to-typescript/node_modules/json-schema-ref-parser": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", - "integrity": "sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q==", - "deprecated": "Please switch to @apidevtools/json-schema-ref-parser", - "dev": true, - "dependencies": { - "@apidevtools/json-schema-ref-parser": "9.0.9" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -5605,22 +5408,6 @@ "node": ">= 0.6" } }, - "node_modules/memoizee": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", - "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.53", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - } - }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -5706,6 +5493,15 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", @@ -6094,12 +5890,6 @@ "node": ">= 0.6" } }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true - }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -6496,40 +6286,6 @@ "set-blocking": "^2.0.0" } }, - "node_modules/nunjucks": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.3.tgz", - "integrity": "sha512-psb6xjLj47+fE76JdZwskvwG4MYsQKXUtMsPh6U0YMvmyjRtKRFcxnlXGWglNybtNTNVmGdp94K62/+NjF5FDQ==", - "dev": true, - "dependencies": { - "a-sync-waterfall": "^1.0.0", - "asap": "^2.0.3", - "commander": "^5.1.0" - }, - "bin": { - "nunjucks-precompile": "bin/precompile" - }, - "engines": { - "node": ">= 6.9.0" - }, - "peerDependencies": { - "chokidar": "^3.3.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/nunjucks/node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", @@ -6823,6 +6579,15 @@ "wrappy": "1" } }, + "node_modules/ono": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/ono/-/ono-4.0.11.tgz", + "integrity": "sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g==", + "dev": true, + "dependencies": { + "format-util": "^1.0.3" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -6909,12 +6674,6 @@ "node": ">=8" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6992,6 +6751,12 @@ "node": ">=8" } }, + "node_modules/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 + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -7118,15 +6883,6 @@ "node": ">=8" } }, - "node_modules/pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/postcss": { "version": "8.4.21", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", @@ -7289,76 +7045,6 @@ } ] }, - "node_modules/quicktype-core": { - "version": "6.1.12", - "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-6.1.12.tgz", - "integrity": "sha512-pBV0VbYZEKIG49xaKGHCat6zlUbg1w15fDf3rnbV2IbG3Ec3T7e46V/dIgL+OGWFphjEZ6n7dcWZiogOk9Adtg==", - "dev": true, - "dependencies": { - "@mark.probst/unicode-properties": "~1.1.0", - "browser-or-node": "^1.2.1", - "collection-utils": "^1.0.1", - "is-url": "^1.2.4", - "isomorphic-fetch": "^2.2.1", - "js-base64": "^2.4.3", - "pako": "^1.0.6", - "pluralize": "^7.0.0", - "readable-stream": "2.3.0", - "urijs": "^1.19.1", - "wordwrap": "^1.0.0", - "yaml": "^1.5.0" - } - }, - "node_modules/quicktype-core/node_modules/process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha512-yN0WQmuCX63LP/TMvAg31nvT6m4vDqJEiiv2CAZqWOGNWutc9DfDk1NPYYmKUFmaVM2UwDowH4u5AHWYP/jxKw==", - "dev": true - }, - "node_modules/quicktype-core/node_modules/readable-stream": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.0.tgz", - "integrity": "sha512-c7KMXGd4b48nN3OJ1U9qOsn6pXNzf6kLd3kdZCkg2sxAcoiufInqF0XckwEnlrcwuaYwonlNK8GQUIOC/WC7sg==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "safe-buffer": "~5.1.0", - "string_decoder": "~1.0.0", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/quicktype-core/node_modules/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==", - "dev": true - }, - "node_modules/quicktype-core/node_modules/string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/quote-stream": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/quote-stream/-/quote-stream-1.0.2.tgz", - "integrity": "sha512-kKr2uQ2AokadPjvTyKJQad9xELbZwYzWlNfI3Uz2j/ib5u6H9lDP7fUUR//rMycd0gv4Z5P1qXMfXR8YpIxrjQ==", - "dev": true, - "dependencies": { - "buffer-equal": "0.0.1", - "minimist": "^1.1.3", - "through2": "^2.0.0" - }, - "bin": { - "quote-stream": "bin/cmd.js" - } - }, "node_modules/randexp": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz", @@ -8021,6 +7707,12 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "dev": true + }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -8127,12 +7819,6 @@ "node": ">=8" } }, - "node_modules/shallow-copy": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", - "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==", - "dev": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -9112,12 +8798,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -9603,12 +9283,6 @@ "node": ">=0.10.0" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", diff --git a/services/device/src/database/dataSource.ts b/services/device/src/database/dataSource.ts index 278c73e4..4830da74 100644 --- a/services/device/src/database/dataSource.ts +++ b/services/device/src/database/dataSource.ts @@ -1,17 +1,9 @@ import { deviceRepository } from './repositories/device' -import { concreteDeviceRepository } from './repositories/device/concreteDevice' -import { deviceGroupRepository } from './repositories/device/deviceGroup' -import { instantiableBrowserDeviceRepository } from './repositories/device/instantiableBrowserDevice' -import { instantiableCloudDeviceRepository } from './repositories/device/instantiableCloudDevice' import { peerconnectionRepository } from './repositories/peerconnection' import { AbstractApplicationDataSource } from '@crosslab/service-common' class ApplicationDataSource extends AbstractApplicationDataSource { protected initializeRepositories(): void { - concreteDeviceRepository.initialize(this) - deviceGroupRepository.initialize(this) - instantiableBrowserDeviceRepository.initialize(this) - instantiableCloudDeviceRepository.initialize(this) deviceRepository.initialize(this) peerconnectionRepository.initialize(this) } diff --git a/services/device/src/database/model.ts b/services/device/src/database/model.ts index 59bcbb9e..31251d0b 100644 --- a/services/device/src/database/model.ts +++ b/services/device/src/database/model.ts @@ -60,17 +60,17 @@ export class ConcreteDeviceModel extends DeviceOverviewModel { @Column() type!: 'device' @Column() - connected?: boolean + connected!: boolean @Column('simple-json') - announcedAvailability?: Required[] + announcedAvailability!: Required[] @Column('simple-json') - availabilityRules?: AvailabilityRule[] + availabilityRules!: AvailabilityRule[] @Column() experiment?: string @Column() token?: string @Column('simple-json') - services?: ServiceDescription[] + services!: ServiceDescription[] @ManyToOne( () => InstantiableDeviceOverviewModel, (instantiableDevice) => instantiableDevice.instances @@ -83,7 +83,7 @@ export class DeviceGroupModel extends DeviceOverviewModel { @Column() type!: 'group' @Column('simple-json') - devices?: DeviceReference[] + devices!: DeviceReference[] } @ChildEntity('cloud instantiable') diff --git a/services/device/src/database/repositories/device.ts b/services/device/src/database/repositories/device.ts index e407f847..166c352c 100644 --- a/services/device/src/database/repositories/device.ts +++ b/services/device/src/database/repositories/device.ts @@ -1,8 +1,8 @@ import { Device, DeviceUpdate } from '../../generated/types' -import { DeviceModel, DeviceOverviewModel } from '../model' +import { DeviceModel } from '../model' import { concreteDeviceRepository } from './device/concreteDevice' import { deviceGroupRepository } from './device/deviceGroup' -import { DeviceOverviewRepository } from './device/deviceOverview' +import { deviceOverviewRepository } from './device/deviceOverview' import { instantiableBrowserDeviceRepository } from './device/instantiableBrowserDevice' import { instantiableCloudDeviceRepository } from './device/instantiableCloudDevice' import { @@ -10,33 +10,41 @@ import { AbstractRepository, InvalidValueError, } from '@crosslab/service-common' +import { FindManyOptions, FindOneOptions, In } from 'typeorm' export class DeviceRepository extends AbstractRepository< DeviceModel, Device<'request'>, Device<'response'> > { + private isInitialized: boolean = false + constructor() { super('Device') } initialize(AppDataSource: AbstractApplicationDataSource): void { - this.repository = AppDataSource.getRepository(DeviceOverviewModel) + deviceOverviewRepository.initialize(AppDataSource) + concreteDeviceRepository.initialize(AppDataSource) + deviceGroupRepository.initialize(AppDataSource) + instantiableBrowserDeviceRepository.initialize(AppDataSource) + instantiableCloudDeviceRepository.initialize(AppDataSource) + + this.isInitialized = true } - async create(data?: Device<'request'>): Promise { - if (!this.repository) this.throwUninitializedRepositoryError() - if (!data) return await super.create() + async create(data: Device<'request'>): Promise { + if (!this.isInitialized) this.throwUninitializedRepositoryError() switch (data.type) { case 'cloud instantiable': - return instantiableCloudDeviceRepository.create(data) + return await instantiableCloudDeviceRepository.create(data) case 'device': - return concreteDeviceRepository.create(data) + return await concreteDeviceRepository.create(data) case 'edge instantiable': - return instantiableBrowserDeviceRepository.create(data) + return await instantiableBrowserDeviceRepository.create(data) case 'group': - return deviceGroupRepository.create(data) + return await deviceGroupRepository.create(data) } } @@ -75,10 +83,8 @@ export class DeviceRepository extends AbstractRepository< async format( model: DeviceModel, - options?: { flatGroup?: boolean; overview?: boolean } + options?: { flatGroup?: boolean } ): Promise> { - if (options?.overview) return await DeviceOverviewRepository.format(model) - switch (model.type) { case 'cloud instantiable': return await instantiableCloudDeviceRepository.format(model) @@ -92,7 +98,7 @@ export class DeviceRepository extends AbstractRepository< } async save(model: DeviceModel): Promise { - if (!this.repository) this.throwUninitializedRepositoryError() + if (!this.isInitialized) this.throwUninitializedRepositoryError() switch (model.type) { case 'cloud instantiable': @@ -105,6 +111,114 @@ export class DeviceRepository extends AbstractRepository< return await deviceGroupRepository.save(model) } } + + async find( + options?: FindManyOptions | undefined + ): Promise { + if (!this.isInitialized) this.throwUninitializedRepositoryError() + + const foundDevices = [] + const deviceOverviews = await deviceOverviewRepository.find(options) + + const deviceTypes = [ + 'device', + 'group', + 'edge instantiable', + 'cloud instantiable', + ] as const + + const repositoryMapping = { + 'device': concreteDeviceRepository, + 'group': deviceGroupRepository, + 'edge instantiable': instantiableBrowserDeviceRepository, + 'cloud instantiable': instantiableCloudDeviceRepository, + } as const + + for (const type of deviceTypes) { + const devices = deviceOverviews.filter((device) => device.type === type) + + if (devices.length > 0) { + foundDevices.push( + ...(await repositoryMapping[type].find({ + where: { + uuid: In( + devices.map((concreteDevice) => concreteDevice.uuid) + ), + }, + })) + ) + } + } + + return foundDevices + } + + async findOne(options: FindOneOptions): Promise { + if (!this.isInitialized) this.throwUninitializedRepositoryError() + + const deviceOverview = await deviceOverviewRepository.findOne(options) + + if (!deviceOverview) return null + + switch (deviceOverview.type) { + case 'cloud instantiable': + return await instantiableCloudDeviceRepository.findOne({ + where: { uuid: deviceOverview.uuid }, + }) + case 'device': + return await concreteDeviceRepository.findOne({ + where: { uuid: deviceOverview.uuid }, + }) + case 'edge instantiable': + return await instantiableBrowserDeviceRepository.findOne({ + where: { uuid: deviceOverview.uuid }, + }) + case 'group': + return await deviceGroupRepository.findOne({ + where: { uuid: deviceOverview.uuid }, + }) + } + } + + async findOneOrFail(options: FindOneOptions): Promise { + if (!this.isInitialized) this.throwUninitializedRepositoryError() + + const deviceOverview = await deviceOverviewRepository.findOneOrFail(options) + + switch (deviceOverview.type) { + case 'cloud instantiable': + return await instantiableCloudDeviceRepository.findOneOrFail({ + where: { uuid: deviceOverview.uuid }, + }) + case 'device': + return await concreteDeviceRepository.findOneOrFail({ + where: { uuid: deviceOverview.uuid }, + }) + case 'edge instantiable': + return await instantiableBrowserDeviceRepository.findOneOrFail({ + where: { uuid: deviceOverview.uuid }, + }) + case 'group': + return await deviceGroupRepository.findOneOrFail({ + where: { uuid: deviceOverview.uuid }, + }) + } + } + + async remove(model: DeviceModel): Promise { + if (!this.isInitialized) this.throwUninitializedRepositoryError() + + switch (model.type) { + case 'cloud instantiable': + return await instantiableCloudDeviceRepository.remove(model) + case 'device': + return await concreteDeviceRepository.remove(model) + case 'edge instantiable': + return await instantiableBrowserDeviceRepository.remove(model) + case 'group': + return await deviceGroupRepository.remove(model) + } + } } export const deviceRepository = new DeviceRepository() diff --git a/services/device/src/database/repositories/device/concreteDevice.ts b/services/device/src/database/repositories/device/concreteDevice.ts index 2fae1cab..9ec1de00 100644 --- a/services/device/src/database/repositories/device/concreteDevice.ts +++ b/services/device/src/database/repositories/device/concreteDevice.ts @@ -1,6 +1,6 @@ import { ConcreteDevice, ConcreteDeviceUpdate } from '../../../generated/types' import { ConcreteDeviceModel } from '../../model' -import { DeviceOverviewRepository } from './deviceOverview' +import { deviceOverviewRepository } from './deviceOverview' import { AbstractApplicationDataSource, AbstractRepository, @@ -22,7 +22,10 @@ export class ConcreteDeviceRepository extends AbstractRepository< async create(data?: ConcreteDevice<'request'>): Promise { const model = await super.create(data) model.type = 'device' + model.announcedAvailability = [] + model.availabilityRules = [] model.connected = false + model.services = [] return model } @@ -30,19 +33,19 @@ export class ConcreteDeviceRepository extends AbstractRepository< model: ConcreteDeviceModel, data: ConcreteDeviceUpdate<'request'> ): Promise { - await DeviceOverviewRepository.write(model, data) + await deviceOverviewRepository.write(model, data) if (data.experiment) model.experiment = data.experiment if (data.services) model.services = data.services } async format(model: ConcreteDeviceModel): Promise> { return { - ...(await DeviceOverviewRepository.format(model)), + ...(await deviceOverviewRepository.format(model)), type: 'device', - announcedAvailability: model.announcedAvailability ?? [], - connected: model.connected ?? false, + announcedAvailability: model.announcedAvailability, + connected: model.connected, experiment: model.experiment ?? undefined, - services: model.services ?? undefined, + services: model.services, } } } diff --git a/services/device/src/database/repositories/device/deviceGroup.ts b/services/device/src/database/repositories/device/deviceGroup.ts index c1e9bcb4..a4d216eb 100644 --- a/services/device/src/database/repositories/device/deviceGroup.ts +++ b/services/device/src/database/repositories/device/deviceGroup.ts @@ -6,7 +6,7 @@ import { } from '../../../generated/types' import { apiClient } from '../../../globals' import { DeviceGroupModel } from '../../model' -import { DeviceOverviewRepository } from './deviceOverview' +import { deviceOverviewRepository } from './deviceOverview' import { AbstractApplicationDataSource, AbstractRepository, @@ -35,9 +35,9 @@ export class DeviceGroupRepository extends AbstractRepository< model: DeviceGroupModel, data: DeviceGroupUpdate<'request'> ): Promise { - await DeviceOverviewRepository.write(model, data) + await deviceOverviewRepository.write(model, data) - model.devices = data.devices + model.devices = data.devices ?? [] } async format( @@ -45,12 +45,12 @@ export class DeviceGroupRepository extends AbstractRepository< flatGroup?: boolean ): Promise> { const devices: Device[] = await this.resolveDeviceReferences( - model.devices ?? [], + model.devices, flatGroup ) return { - ...(await DeviceOverviewRepository.format(model)), + ...(await deviceOverviewRepository.format(model)), type: 'group', devices: devices.filter( (value, index, array) => @@ -71,9 +71,7 @@ export class DeviceGroupRepository extends AbstractRepository< if (!device) continue if (device.type === 'group' && flatGroup) { - devices.push( - ...(await this.resolveDeviceReferences(device.devices ?? [])) - ) + devices.push(...(await this.resolveDeviceReferences(device.devices))) } else { devices.push(device) } diff --git a/services/device/src/database/repositories/device/deviceOverview.ts b/services/device/src/database/repositories/device/deviceOverview.ts index 58858444..0e34050f 100644 --- a/services/device/src/database/repositories/device/deviceOverview.ts +++ b/services/device/src/database/repositories/device/deviceOverview.ts @@ -1,14 +1,25 @@ import { DeviceOverview, DeviceOverviewUpdate } from '../../../generated/types' import { deviceUrlFromId } from '../../../methods/urlFromId' import { DeviceOverviewModel } from '../../model' -import { AbstractRepository } from '@crosslab/service-common' +import { + AbstractApplicationDataSource, + AbstractRepository, +} from '@crosslab/service-common' -export abstract class DeviceOverviewRepository extends AbstractRepository< +class DeviceOverviewRepository extends AbstractRepository< DeviceOverviewModel, DeviceOverview<'request'>, DeviceOverview<'response'> > { - static async write( + constructor() { + super('Device Overview') + } + + initialize(AppDataSource: AbstractApplicationDataSource): void { + this.repository = AppDataSource.getRepository(DeviceOverviewModel) + } + + async write( model: DeviceOverviewModel, data: DeviceOverviewUpdate<'request'> ): Promise { @@ -16,7 +27,7 @@ export abstract class DeviceOverviewRepository extends AbstractRepository< if (data.description) model.description = data.description } - static async format(model: DeviceOverviewModel): Promise> { + async format(model: DeviceOverviewModel): Promise> { return { url: deviceUrlFromId(model.uuid), type: model.type, @@ -26,3 +37,5 @@ export abstract class DeviceOverviewRepository extends AbstractRepository< } } } + +export const deviceOverviewRepository = new DeviceOverviewRepository() diff --git a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts index a7776559..621cc111 100644 --- a/services/device/src/database/repositories/device/instantiableBrowserDevice.ts +++ b/services/device/src/database/repositories/device/instantiableBrowserDevice.ts @@ -3,7 +3,7 @@ import { InstantiableBrowserDeviceUpdate, } from '../../../generated/types' import { InstantiableBrowserDeviceModel } from '../../model' -import { DeviceOverviewRepository } from './deviceOverview' +import { deviceOverviewRepository } from './deviceOverview' import { AbstractApplicationDataSource, AbstractRepository, @@ -34,7 +34,7 @@ export class InstantiableBrowserDeviceRepository extends AbstractRepository< model: InstantiableBrowserDeviceModel, data: InstantiableBrowserDeviceUpdate<'request'> ) { - await DeviceOverviewRepository.write(model, data) + await deviceOverviewRepository.write(model, data) model.codeUrl = data.codeUrl model.services = data.services @@ -44,7 +44,7 @@ export class InstantiableBrowserDeviceRepository extends AbstractRepository< model: InstantiableBrowserDeviceModel ): Promise> { return { - ...(await DeviceOverviewRepository.format(model)), + ...(await deviceOverviewRepository.format(model)), type: 'edge instantiable', codeUrl: model.codeUrl, services: model.services ?? undefined, diff --git a/services/device/src/database/repositories/device/instantiableCloudDevice.ts b/services/device/src/database/repositories/device/instantiableCloudDevice.ts index bd61e174..2487b152 100644 --- a/services/device/src/database/repositories/device/instantiableCloudDevice.ts +++ b/services/device/src/database/repositories/device/instantiableCloudDevice.ts @@ -3,7 +3,7 @@ import { InstantiableCloudDeviceUpdate, } from '../../../generated/types' import { InstantiableCloudDeviceModel } from '../../model' -import { DeviceOverviewRepository } from './deviceOverview' +import { deviceOverviewRepository } from './deviceOverview' import { AbstractApplicationDataSource, AbstractRepository, @@ -34,7 +34,7 @@ export class InstantiableCloudDeviceRepository extends AbstractRepository< model: InstantiableCloudDeviceModel, data: InstantiableCloudDeviceUpdate<'request'> ) { - await DeviceOverviewRepository.write(model, data) + await deviceOverviewRepository.write(model, data) model.instantiateUrl = data.instantiateUrl model.services = data.services @@ -44,7 +44,7 @@ export class InstantiableCloudDeviceRepository extends AbstractRepository< model: InstantiableCloudDeviceModel ): Promise> { return { - ...(await DeviceOverviewRepository.format(model)), + ...(await deviceOverviewRepository.format(model)), type: 'cloud instantiable', instantiateUrl: model.instantiateUrl, services: model.services ?? undefined, diff --git a/services/device/src/operations/devices/device/post.ts b/services/device/src/operations/devices/device/post.ts index 8748ff8c..49e17aa5 100644 --- a/services/device/src/operations/devices/device/post.ts +++ b/services/device/src/operations/devices/device/post.ts @@ -1,20 +1,11 @@ import { deviceRepository } from '../../../database/repositories/device' import { concreteDeviceRepository } from '../../../database/repositories/device/concreteDevice' import { postDevicesByDeviceIdSignature } from '../../../generated/signatures' -import { ErrorWithStatus } from '../../../generated/types' import { apiClient } from '../../../globals' import { changedCallbacks } from '../../../methods/callbacks' import { deviceUrlFromId } from '../../../methods/urlFromId' import { ForbiddenOperationError } from '@crosslab/service-common' -// TODO: rethink how to handle this problem (required JWT user) -export class UnauthorizedError extends ErrorWithStatus { - constructor(message: string, status?: number) { - super(message, status) - this.name = 'UnauthorizedError' - } -} - /** * This function implements the functionality for handling POST requests on /devices/{device_id} endpoint. * @param parameters The parameters of the request. @@ -28,9 +19,6 @@ export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( ) => { console.log(`postDevicesByDeviceId called`) - // TODO: rethink how to handle this problem (required JWT user) - if (!user.JWT) throw new UnauthorizedError('User is not authorized', 401) - const instantiableDeviceModel = await deviceRepository.findOneOrFail({ where: { uuid: parameters.device_id }, }) @@ -47,10 +35,8 @@ export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( ) const concreteDeviceModel = await concreteDeviceRepository.create({ - services: [], ...(await deviceRepository.format(instantiableDeviceModel)), type: 'device', - announcedAvailability: [{ available: true }], }) concreteDeviceModel.owner = user.JWT?.url diff --git a/services/device/src/operations/devices/get.ts b/services/device/src/operations/devices/get.ts index cd77eb64..b63051fe 100644 --- a/services/device/src/operations/devices/get.ts +++ b/services/device/src/operations/devices/get.ts @@ -1,4 +1,5 @@ import { deviceRepository } from '../../database/repositories/device' +import { deviceOverviewRepository } from '../../database/repositories/device/deviceOverview' import { getDevicesSignature } from '../../generated/signatures' /** @@ -15,9 +16,7 @@ export const getDevices: getDevicesSignature = async (_user) => { return { status: 200, body: await Promise.all( - deviceModels.map((device) => - deviceRepository.format(device, { overview: true }) - ) + deviceModels.map((device) => deviceOverviewRepository.format(device)) ), } } diff --git a/services/device/src/operations/devices/post.ts b/services/device/src/operations/devices/post.ts index 894e8da6..37117ccf 100644 --- a/services/device/src/operations/devices/post.ts +++ b/services/device/src/operations/devices/post.ts @@ -1,4 +1,3 @@ -import { UnauthorizedError } from '.' import { deviceRepository } from '../../database/repositories/device' import { postDevicesSignature } from '../../generated/signatures' import { changedCallbacks } from '../../methods/callbacks' @@ -12,11 +11,8 @@ import { changedCallbacks } from '../../methods/callbacks' export const postDevices: postDevicesSignature = async (parameters, body, user) => { console.log(`postDevices called`) - // TODO: rethink how to handle this problem (required JWT user) - if (!user.JWT) throw new UnauthorizedError('User is not authorized', 401) - const deviceModel = await deviceRepository.create(body) - deviceModel.owner = user.JWT?.url + deviceModel.owner = user.JWT.url await deviceRepository.save(deviceModel) if (parameters.changedUrl) { diff --git a/services/device/src/operations/peerconnections/post.ts b/services/device/src/operations/peerconnections/post.ts index 0b8d8781..6337bd55 100644 --- a/services/device/src/operations/peerconnections/post.ts +++ b/services/device/src/operations/peerconnections/post.ts @@ -45,12 +45,12 @@ export const postPeerconnections: postPeerconnectionsSignature = async ( // register changed callbacks for devices to get notified when they connect const n_deviceA = await apiClient.updateDevice( deviceA.url, - {}, + { type: 'device' }, { changedUrl: callbackUrl } ) const n_deviceB = await apiClient.updateDevice( deviceB.url, - {}, + { type: 'device' }, { changedUrl: callbackUrl } ) diff --git a/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts b/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts index 82b690a9..7fe9d3db 100644 --- a/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts +++ b/services/device/test/data/devices/concreteDevices/concrete_device.spec.ts @@ -21,6 +21,9 @@ const concrete_device: EntityData = { description, owner, announcedAvailability: [], + services: [], + availabilityRules: [], + connected: false, }, response: { url: deviceUrlFromId(uuid), @@ -30,6 +33,7 @@ const concrete_device: EntityData = { owner, connected: false, announcedAvailability: [], + services: [], }, } diff --git a/services/device/test/database/repositories/device.spec.ts b/services/device/test/database/repositories/device.spec.ts index ae6fb43b..84a4ec34 100644 --- a/services/device/test/database/repositories/device.spec.ts +++ b/services/device/test/database/repositories/device.spec.ts @@ -61,6 +61,11 @@ class DeviceRepositoryTestSuite extends AbstractRepositoryTestSuite< return testSuite }) + + // remove this test since input is needed for this repository's create function + this.testSuites.create.tests = this.testSuites.create.tests.filter( + (test) => test.title !== 'should create a model from empty data' + ) } validateCreate(model: DeviceModel, data?: Device<'request'> | undefined): boolean { diff --git a/services/device/test/methods/callbacks.spec.ts b/services/device/test/methods/callbacks.spec.ts index 5eb7b8bf..f0190da1 100644 --- a/services/device/test/methods/callbacks.spec.ts +++ b/services/device/test/methods/callbacks.spec.ts @@ -34,6 +34,10 @@ export default () => uuid: 'ea2a852d-b16c-45e0-819f-0af793bb596e', name: 'Test Device', owner: 'http://localhost', + announcedAvailability: [], + availabilityRules: [], + connected: false, + services: [], } TEST_PEERCONNECTION_MODEL = { uuid: 'ea2a852d-b16c-45e0-819f-0af793bb596e', diff --git a/services/device/test/operations/devices/device/delete.spec.ts b/services/device/test/operations/devices/device/delete.spec.ts index 71fbfc24..03dc1d56 100644 --- a/services/device/test/operations/devices/device/delete.spec.ts +++ b/services/device/test/operations/devices/device/delete.spec.ts @@ -3,7 +3,7 @@ import { deleteDevicesByDeviceId } from '../../../../src/operations/devices' import { deviceNames } from '../../../data/devices/index.spec' import { TestData } from '../../../data/index.spec' import { MissingEntityError } from '@crosslab/service-common' -import assert, { fail } from 'assert' +import assert from 'assert' import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { @@ -53,8 +53,8 @@ export default function (context: Mocha.Context, testData: TestData) { suite.addTest( new Mocha.Test( 'should throw an error if user is not the owner of the device', - async function () { - fail() + async function (this: Mocha.Context) { + this.skip() } ) ) @@ -62,8 +62,8 @@ export default function (context: Mocha.Context, testData: TestData) { suite.addTest( new Mocha.Test( 'superadmin/admin should be able to delete the device', - async function () { - fail() + async function (this: Mocha.Context) { + this.skip() } ) ) diff --git a/services/device/test/operations/devices/device/get.spec.ts b/services/device/test/operations/devices/device/get.spec.ts index 2b40107a..a4c4a444 100644 --- a/services/device/test/operations/devices/device/get.spec.ts +++ b/services/device/test/operations/devices/device/get.spec.ts @@ -19,7 +19,6 @@ export default function (context: Mocha.Context, testData: TestData) { suite.beforeAll(function () { getDeviceStub = sinon.stub(apiClient, 'getDevice') getDeviceStub.callsFake(async (url, options) => { - console.debug(url.split('/').at(-1) ?? 'non-existent') const result = await getDevicesByDeviceId( { device_id: url.split('/').at(-1) ?? 'non-existent', @@ -28,7 +27,6 @@ export default function (context: Mocha.Context, testData: TestData) { testData.userData ) assert(result.status === 200) - console.debug(result.body.name) return result.body }) }) diff --git a/services/device/test/operations/devices/device/post.spec.ts b/services/device/test/operations/devices/device/post.spec.ts index b03aa9be..8f3510b2 100644 --- a/services/device/test/operations/devices/device/post.spec.ts +++ b/services/device/test/operations/devices/device/post.spec.ts @@ -1,11 +1,59 @@ +import { concreteDeviceRepository } from '../../../../src/database/repositories/device/concreteDevice' +import { ConcreteDevice } from '../../../../src/generated/types' +import { apiClient } from '../../../../src/globals' import { postDevicesByDeviceId } from '../../../../src/operations/devices' +import { instantiableBrowserDeviceNames } from '../../../data/devices/instantiableBrowserDevices/index.spec' +import { instantiableCloudDeviceNames } from '../../../data/devices/instantiableCloudDevices/index.spec' import { TestData } from '../../../data/index.spec' -import { MissingEntityError } from '@crosslab/service-common' +import { concreteDeviceRepositoryTestSuite } from '../../../database/repositories/device/concreteDevice.spec' +import { ForbiddenOperationError, MissingEntityError } from '@crosslab/service-common' import assert from 'assert' import Mocha from 'mocha' +import * as sinon from 'sinon' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('POST /devices/{device_id}', context) + const INSTANCE_UUID = '639845cc-d103-4ec2-91cd-a6a84cdea5d4' + const DEVICE_TOKEN = '15addcf9-74be-4057-80af-cf85cff08b03' + let concreteDeviceRepositoryCreateStub: sinon.SinonStub< + Parameters, + ReturnType + > + let createDeviceAuthenticationTokenStub: sinon.SinonStub< + Parameters, + ReturnType + > + + suite.beforeAll(function () { + const originalCreate = concreteDeviceRepository.create.bind( + concreteDeviceRepository + ) + concreteDeviceRepositoryCreateStub = sinon.stub( + concreteDeviceRepository, + 'create' + ) + concreteDeviceRepositoryCreateStub.callsFake(async function ( + data?: ConcreteDevice<'request'> + ) { + const concreteDeviceModel = await originalCreate(data) + concreteDeviceModel.uuid = INSTANCE_UUID + return concreteDeviceModel + }) + + createDeviceAuthenticationTokenStub = sinon.stub( + apiClient, + 'createDeviceAuthenticationToken' + ) + createDeviceAuthenticationTokenStub.resolves(DEVICE_TOKEN) + }) + + suite.afterEach(function () { + createDeviceAuthenticationTokenStub.resetHistory() + }) + + suite.afterAll(function () { + createDeviceAuthenticationTokenStub.restore() + }) suite.addTest( new Mocha.Test( @@ -28,5 +76,81 @@ export default function (context: Mocha.Context, testData: TestData) { ) ) + suite.addTest( + new Mocha.Test( + 'should throw a ForbiddenOperationError if the device is not instantiable', + async function () { + const deviceModels = [ + testData['concrete devices']['concrete device'].model, + testData['device groups']['device group'].model, + ] + + for (const deviceModel of deviceModels) { + await assert.rejects( + async () => { + await postDevicesByDeviceId( + { + device_id: deviceModel.uuid, + }, + testData.userData + ) + }, + (error) => { + assert(error instanceof ForbiddenOperationError) + assert(error.status === 400) + return true + } + ) + } + } + ) + ) + + const instantiableDevices = { + ...testData['instantiable browser devices'], + ...testData['instantiable cloud devices'], + } + + for (const instantiableDeviceName of [ + ...instantiableBrowserDeviceNames, + ...instantiableCloudDeviceNames, + ]) { + suite.addTest( + new Mocha.Test( + `should successfully instantiate an instantiable device (${instantiableDeviceName})`, + async function () { + const deviceModel = instantiableDevices[instantiableDeviceName].model + + const result = await postDevicesByDeviceId( + { device_id: deviceModel.uuid }, + testData.userData + ) + + assert(result.status === 201) + assert(result.body.deviceToken === DEVICE_TOKEN) + const instanceModel = await concreteDeviceRepository.findOneOrFail({ + where: { uuid: INSTANCE_UUID }, + }) + + assert( + concreteDeviceRepositoryTestSuite.validateFormat( + instanceModel, + result.body.instance + ) + ) + } + ) + ) + } + + suite.addTest( + new Mocha.Test( + 'should register changed-callback for created instance', + async function (this: Mocha.Context) { + this.skip() + } + ) + ) + return suite } diff --git a/services/device/test/operations/devices/post.spec.ts b/services/device/test/operations/devices/post.spec.ts index fa974c0b..9be2bfa5 100644 --- a/services/device/test/operations/devices/post.spec.ts +++ b/services/device/test/operations/devices/post.spec.ts @@ -1,7 +1,7 @@ import { DeviceRepository } from '../../../src/database/repositories/device' import { apiClient } from '../../../src/globals' import { changedCallbacks } from '../../../src/methods/callbacks' -import { postDevices, UnauthorizedError } from '../../../src/operations/devices' +import { postDevices } from '../../../src/operations/devices' import { deviceNames } from '../../data/devices/index.spec' import { TestData } from '../../data/index.spec' import { deviceRepositoryTestSuite } from '../../database/repositories/device.spec' @@ -27,7 +27,6 @@ export default function (context: Mocha.Context, testData: TestData) { suite.afterAll(function () { getDeviceStub.restore() - console.debug('afterAll executed') }) async function createDevice( @@ -64,13 +63,16 @@ export default function (context: Mocha.Context, testData: TestData) { assert(changedCallbacks.get(device.model.uuid) === changedUrl) } - suite.addTest( - new Mocha.Test('should create a new device', async function () { - for (const deviceName of deviceNames) { - await createDevice(testData.devices[deviceName]) - } - }) - ) + for (const deviceName of deviceNames) { + suite.addTest( + new Mocha.Test( + `should create a new device (${deviceName})`, + async function () { + await createDevice(testData.devices[deviceName]) + } + ) + ) + } suite.addTest( new Mocha.Test( @@ -86,27 +88,5 @@ export default function (context: Mocha.Context, testData: TestData) { ) ) - suite.addTest( - new Mocha.Test( - 'should throw an error if no UserData for JWT is provided', - async function () { - await assert.rejects( - async () => { - await postDevices( - {}, - testData.devices['concrete device'].request, - testData.userData - ) - }, - (error) => { - assert(error instanceof UnauthorizedError) - assert(error.status === 401) - return true - } - ) - } - ) - ) - return suite } diff --git a/services/openapi/dist/openapi.json b/services/openapi/dist/openapi.json index 9f6eee0c..19078f20 100644 --- a/services/openapi/dist/openapi.json +++ b/services/openapi/dist/openapi.json @@ -315,38 +315,6 @@ "x-typeguard": true, "x-service-name": "Device Service" }, - "device_overview_init": { - "title": "Device Overview Init", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the device", - "writeOnly": true - }, - "description": { - "type": "string", - "description": "Extended description of the device, features, etc.", - "writeOnly": true - }, - "type": { - "type": "string", - "description": "Type of the device", - "enum": [ - "device", - "group", - "edge instantiable", - "cloud instantiable" - ], - "writeOnly": true - } - }, - "required": [ - "type", - "name" - ], - "x-service-name": "Device Service" - }, "service_description": { "title": "Service Description", "type": "object", @@ -370,166 +338,6 @@ "additionalProperties": true, "x-service-name": "Device Service" }, - "device_cloud_instantiable_init": { - "title": "Instantiable Cloud Device Init", - "allOf": [ - { - "$ref": "#/components/schemas/device_overview_init" - }, - { - "type": "object", - "properties": { - "type": { - "const": "cloud instantiable", - "writeOnly": true - }, - "instantiateUrl": { - "type": "string", - "format": "uri", - "writeOnly": true - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true - } - }, - "required": [ - "type" - ] - } - ], - "x-service-name": "Device Service" - }, - "device_concrete_init": { - "title": "Concrete Device Init", - "allOf": [ - { - "$ref": "#/components/schemas/device_overview_init" - }, - { - "type": "object", - "properties": { - "type": { - "const": "device", - "writeOnly": true - }, - "experiment": { - "type": "string", - "format": "uri", - "writeOnly": true - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true - } - }, - "required": [ - "type" - ] - } - ], - "x-service-name": "Device Service" - }, - "device_edge_instantiable_init": { - "title": "Instantiable Browser Device Init", - "allOf": [ - { - "$ref": "#/components/schemas/device_overview_init" - }, - { - "type": "object", - "properties": { - "type": { - "const": "edge instantiable", - "writeOnly": true - }, - "codeUrl": { - "type": "string", - "format": "uri", - "writeOnly": true - }, - "services": { - "type": "array", - "items": { - "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true - } - }, - "required": [ - "type" - ] - } - ], - "x-service-name": "Device Service" - }, - "device_reference": { - "title": "Device Reference", - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "URL of the device", - "format": "uri" - } - }, - "required": [ - "url" - ], - "x-service-name": "Device Service" - }, - "device_group_init": { - "title": "Device Group Init", - "allOf": [ - { - "$ref": "#/components/schemas/device_overview_init" - }, - { - "type": "object", - "properties": { - "type": { - "const": "group", - "writeOnly": true - }, - "devices": { - "type": "array", - "items": { - "$ref": "#/components/schemas/device_reference" - }, - "writeOnly": true - } - }, - "required": [ - "type" - ] - } - ], - "x-service-name": "Device Service" - }, - "device_init": { - "title": "Device Init", - "oneOf": [ - { - "$ref": "#/components/schemas/device_cloud_instantiable_init" - }, - { - "$ref": "#/components/schemas/device_concrete_init" - }, - { - "$ref": "#/components/schemas/device_edge_instantiable_init" - }, - { - "$ref": "#/components/schemas/device_group_init" - } - ], - "x-service-name": "Device Service" - }, "device_cloud_instantiable": { "title": "Instantiable Cloud Device", "allOf": [ @@ -647,6 +455,21 @@ "x-typeguard": true, "x-service-name": "Device Service" }, + "device_reference": { + "title": "Device Reference", + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL of the device", + "format": "uri" + } + }, + "required": [ + "url" + ], + "x-service-name": "Device Service" + }, "device_group": { "title": "Device Group", "allOf": [ @@ -665,7 +488,10 @@ "$ref": "#/components/schemas/device_reference" } } - } + }, + "required": [ + "devices" + ] } ], "x-typeguard": true, @@ -673,7 +499,7 @@ }, "device": { "title": "Device", - "oneOf": [ + "anyOf": [ { "$ref": "#/components/schemas/device_cloud_instantiable" }, @@ -687,6 +513,7 @@ "$ref": "#/components/schemas/device_group" } ], + "x-typeguard": true, "x-service-name": "Device Service" }, "device_overview_update": { @@ -695,20 +522,30 @@ "properties": { "name": { "type": "string", - "description": "Name of the device", - "writeOnly": true + "description": "Name of the device" }, "description": { "type": "string", - "description": "Extended description of the device, features, etc.", - "writeOnly": true + "description": "Extended description of the device, features, etc." + }, + "type": { + "type": "string", + "description": "Type of the device", + "enum": [ + "device", + "group", + "edge instantiable", + "cloud instantiable" + ] } }, + "required": [ + "type" + ], "x-service-name": "Device Service" }, "device_cloud_instantiable_update": { "title": "Instantiable Cloud Device Update", - "type": "object", "allOf": [ { "$ref": "#/components/schemas/device_overview_update" @@ -716,27 +553,26 @@ { "type": "object", "properties": { + "type": { + "const": "cloud instantiable" + }, "instantiateUrl": { "type": "string", - "format": "uri", - "writeOnly": true + "format": "uri" }, "services": { "type": "array", "items": { "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true + } } } } ], - "additionalProperties": false, "x-service-name": "Device Service" }, "device_concrete_update": { "title": "Concrete Device Update", - "type": "object", "allOf": [ { "$ref": "#/components/schemas/device_overview_update" @@ -744,27 +580,26 @@ { "type": "object", "properties": { + "type": { + "const": "device" + }, "experiment": { "type": "string", - "format": "uri", - "writeOnly": true + "format": "uri" }, "services": { "type": "array", "items": { "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true + } } } } ], - "additionalProperties": false, "x-service-name": "Device Service" }, "device_edge_instantiable_update": { "title": "Instantiable Browser Device Update", - "type": "object", "allOf": [ { "$ref": "#/components/schemas/device_overview_update" @@ -772,27 +607,26 @@ { "type": "object", "properties": { + "type": { + "const": "edge instantiable" + }, "codeUrl": { "type": "string", - "format": "uri", - "writeOnly": true + "format": "uri" }, "services": { "type": "array", "items": { "$ref": "#/components/schemas/service_description" - }, - "writeOnly": true + } } } } ], - "additionalProperties": false, "x-service-name": "Device Service" }, "device_group_update": { "title": "Device Group Update", - "type": "object", "allOf": [ { "$ref": "#/components/schemas/device_overview_update" @@ -800,22 +634,23 @@ { "type": "object", "properties": { + "type": { + "const": "group" + }, "devices": { "type": "array", "items": { "$ref": "#/components/schemas/device_reference" - }, - "writeOnly": true + } } } } ], - "additionalProperties": false, "x-service-name": "Device Service" }, "device_update": { "title": "Device Update", - "oneOf": [ + "anyOf": [ { "$ref": "#/components/schemas/device_cloud_instantiable_update" }, @@ -853,9 +688,7 @@ "enum": [ "HOURLY", "DAILY", - "WEEKLY", - "MONTHLY", - "YEARLY" + "WEEKLY" ] }, "until": { @@ -867,7 +700,10 @@ "description": "How often the time slot will be repeated", "type": "integer" } - } + }, + "required": [ + "frequency" + ] } } } @@ -3359,7 +3195,7 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/device_init" + "$ref": "#/components/schemas/device" }, "examples": { "microcontroller": { @@ -4232,7 +4068,11 @@ "deviceToken": { "type": "string" } - } + }, + "required": [ + "instance", + "deviceToken" + ] } } } From 2ab2b6818c1a9c3db2c21991578367e255b00115 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Wed, 19 Apr 2023 10:16:02 +0200 Subject: [PATCH 25/33] Add addTest function to simplify adding test cases --- .../device/test/methods/availability.spec.ts | 11 + .../device/test/methods/callbacks.spec.ts | 2 + .../devices/device/availability/post.spec.ts | 51 +++ .../operations/devices/device/delete.spec.ts | 100 +++--- .../operations/devices/device/get.spec.ts | 89 +++--- .../operations/devices/device/index.spec.ts | 3 +- .../operations/devices/device/patch.spec.ts | 302 +++++++++--------- .../operations/devices/device/post.spec.ts | 172 ++++++---- .../test/operations/devices/get.spec.ts | 35 +- .../test/operations/devices/post.spec.ts | 33 +- services/device/test/operations/index.spec.ts | 9 + .../operations/peerconnections/get.spec.ts | 31 +- 12 files changed, 464 insertions(+), 374 deletions(-) diff --git a/services/device/test/methods/availability.spec.ts b/services/device/test/methods/availability.spec.ts index 0db97579..08467216 100644 --- a/services/device/test/methods/availability.spec.ts +++ b/services/device/test/methods/availability.spec.ts @@ -19,10 +19,12 @@ export default () => rules: AvailabilityRule[] availability: Availability }[] = [ + // empty rules { rules: [], availability: [], }, + // always available { rules: [{ available: true }], availability: [ @@ -32,10 +34,12 @@ export default () => }, ], }, + // never available { rules: [{ available: false }], availability: [], }, + // one rule without repeat { rules: [ { @@ -51,6 +55,7 @@ export default () => }, ], }, + // one rule with HOURLY repeat (count limiting) { rules: [ { @@ -71,6 +76,7 @@ export default () => } }), }, + // one rule with DAILY repeat (until limiting) { rules: [ { @@ -91,6 +97,7 @@ export default () => } }), }, + // one rule with WEEKLY repeat (until stopping second repeat) { rules: [ { @@ -111,6 +118,7 @@ export default () => }, ], }, + // one rule with WEEKLY repeat (until allowing second repeat) { rules: [ { @@ -135,6 +143,7 @@ export default () => }, ], }, + // multiple overlapping and some invalid rules { rules: [ { @@ -176,6 +185,7 @@ export default () => }, ], }, + // one rule with HOURLY repeat (end - start > frequency) { rules: [ { @@ -192,6 +202,7 @@ export default () => }, ], }, + // multiple overlapping rules { rules: [ { diff --git a/services/device/test/methods/callbacks.spec.ts b/services/device/test/methods/callbacks.spec.ts index f0190da1..b66ddc40 100644 --- a/services/device/test/methods/callbacks.spec.ts +++ b/services/device/test/methods/callbacks.spec.ts @@ -99,12 +99,14 @@ export default () => assert(headers) assert(typeof headers.values !== 'string') const headersValues = headers.values() + const firstHeader = headersValues.next() assert(Array.isArray(firstHeader.value)) assert(!firstHeader.done) assert(firstHeader.value.length === 2) assert(firstHeader.value[0] === 'Content-Type') assert(firstHeader.value[1] === 'application/json') + const secondHeader = headersValues.next() assert(secondHeader.done && secondHeader.value === undefined) } diff --git a/services/device/test/operations/devices/device/availability/post.spec.ts b/services/device/test/operations/devices/device/availability/post.spec.ts index 02fdb7e3..0787928b 100644 --- a/services/device/test/operations/devices/device/availability/post.spec.ts +++ b/services/device/test/operations/devices/device/availability/post.spec.ts @@ -1,8 +1,59 @@ +import { postDevicesByDeviceIdAvailability } from '../../../../../src/operations/devices' import { TestData } from '../../../../data/index.spec' +import { addTest } from '../../../index.spec' +import { ForbiddenOperationError, MissingEntityError } from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('POST /devices/{device_id}/availability', context) + addTest( + suite, + 'should throw a MissingEntityError if the device could not be found', + async function () { + await assert.rejects( + async () => { + await postDevicesByDeviceIdAvailability( + { device_id: 'non-existent' }, + [], + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert(error.status === 404) + return true + } + ) + } + ) + + addTest( + suite, + "should throw a ForbiddenOperationError if the device is not of type 'device'", + async function () { + await assert.rejects( + async () => { + await postDevicesByDeviceIdAvailability( + { + device_id: + testData['device groups']['device group'].model.uuid, + }, + [], + testData.userData + ) + }, + (error) => { + assert(error instanceof ForbiddenOperationError) + assert(error.status === 400) + return true + } + ) + } + ) + + addTest(suite, '') + return suite } diff --git a/services/device/test/operations/devices/device/delete.spec.ts b/services/device/test/operations/devices/device/delete.spec.ts index 03dc1d56..dbdd265e 100644 --- a/services/device/test/operations/devices/device/delete.spec.ts +++ b/services/device/test/operations/devices/device/delete.spec.ts @@ -2,6 +2,7 @@ import { deviceRepository } from '../../../../src/database/repositories/device' import { deleteDevicesByDeviceId } from '../../../../src/operations/devices' import { deviceNames } from '../../../data/devices/index.spec' import { TestData } from '../../../data/index.spec' +import { addTest } from '../../index.spec' import { MissingEntityError } from '@crosslab/service-common' import assert from 'assert' import Mocha from 'mocha' @@ -9,63 +10,58 @@ import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('DELETE /devices/{device_id}', context) - suite.addTest( - new Mocha.Test('should delete the device', async function () { - for (const deviceName of deviceNames) { - const deviceModel = testData.devices[deviceName].model - const result = await deleteDevicesByDeviceId( - { device_id: deviceModel.uuid }, - testData.userData - ) - assert(result.status === 204) - assert( - (await deviceRepository.findOne({ - where: { - uuid: deviceModel.uuid, - }, - })) === null - ) - } - }) - ) - - suite.addTest( - new Mocha.Test( - 'should throw a MissingEntityError if device is not found', - async function () { - await assert.rejects( - async () => { - await deleteDevicesByDeviceId( - { device_id: 'non-existent' }, - testData.userData - ) + addTest(suite, 'should delete the device', async function () { + for (const deviceName of deviceNames) { + const deviceModel = testData.devices[deviceName].model + const result = await deleteDevicesByDeviceId( + { device_id: deviceModel.uuid }, + testData.userData + ) + assert(result.status === 204) + assert( + (await deviceRepository.findOne({ + where: { + uuid: deviceModel.uuid, }, - (error) => { - assert(error instanceof MissingEntityError) - assert(error.status === 404) - return true - } - ) - } - ) + })) === null + ) + } + }) + + addTest( + suite, + 'should throw a MissingEntityError if device is not found', + async function () { + await assert.rejects( + async () => { + await deleteDevicesByDeviceId( + { device_id: 'non-existent' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert(error.status === 404) + return true + } + ) + } ) - suite.addTest( - new Mocha.Test( - 'should throw an error if user is not the owner of the device', - async function (this: Mocha.Context) { - this.skip() - } - ) + addTest( + suite, + 'should throw an error if user is not the owner of the device', + async function (this: Mocha.Context) { + this.skip() + } ) - suite.addTest( - new Mocha.Test( - 'superadmin/admin should be able to delete the device', - async function (this: Mocha.Context) { - this.skip() - } - ) + addTest( + suite, + 'superadmin/admin should be able to delete the device', + async function (this: Mocha.Context) { + this.skip() + } ) return suite diff --git a/services/device/test/operations/devices/device/get.spec.ts b/services/device/test/operations/devices/device/get.spec.ts index a4c4a444..9287aad6 100644 --- a/services/device/test/operations/devices/device/get.spec.ts +++ b/services/device/test/operations/devices/device/get.spec.ts @@ -4,6 +4,7 @@ import { deviceGroupNames } from '../../../data/devices/deviceGroups/index.spec' import { deviceNames } from '../../../data/devices/index.spec' import { TestData } from '../../../data/index.spec' import { deviceRepositoryTestSuite } from '../../../database/repositories/device.spec' +import { addTest } from '../../index.spec' import { MissingEntityError } from '@crosslab/service-common' import assert from 'assert' import Mocha from 'mocha' @@ -35,66 +36,60 @@ export default function (context: Mocha.Context, testData: TestData) { getDeviceStub.restore() }) - suite.addTest( - new Mocha.Test('should return the formatted device', async function () { - for (const deviceName of deviceNames) { - const device = testData.devices[deviceName] + addTest(suite, 'should return the formatted device', async function () { + for (const deviceName of deviceNames) { + const device = testData.devices[deviceName] + const result = await getDevicesByDeviceId( + { device_id: device.model.uuid }, + testData.userData + ) + + assert(result.status === 200) + assert(deviceRepositoryTestSuite.validateFormat(device.model, result.body)) + } + }) + + addTest( + suite, + 'should return the flattened formatted device group', + async function () { + for (const deviceGroupName of deviceGroupNames) { + const deviceGroup = testData['device groups'][deviceGroupName] const result = await getDevicesByDeviceId( - { device_id: device.model.uuid }, + { device_id: deviceGroup.model.uuid, flat_group: true }, testData.userData ) assert(result.status === 200) assert( - deviceRepositoryTestSuite.validateFormat(device.model, result.body) + deviceRepositoryTestSuite.validateFormat( + deviceGroup.model, + result.body, + { flatten: true } + ) ) } - }) + } ) - suite.addTest( - new Mocha.Test( - 'should return the flattened formatted device group', - async function () { - for (const deviceGroupName of deviceGroupNames) { - const deviceGroup = testData['device groups'][deviceGroupName] - const result = await getDevicesByDeviceId( - { device_id: deviceGroup.model.uuid, flat_group: true }, + addTest( + suite, + 'should throw a MissingEntityError if device is not found', + async function () { + await assert.rejects( + async () => { + await getDevicesByDeviceId( + { device_id: 'non-existent' }, testData.userData ) - - assert(result.status === 200) - assert( - deviceRepositoryTestSuite.validateFormat( - deviceGroup.model, - result.body, - { flatten: true } - ) - ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert(error.status === 404) + return true } - } - ) - ) - - suite.addTest( - new Mocha.Test( - 'should throw a MissingEntityError if device is not found', - async function () { - await assert.rejects( - async () => { - await getDevicesByDeviceId( - { device_id: 'non-existent' }, - testData.userData - ) - }, - (error) => { - assert(error instanceof MissingEntityError) - assert(error.status === 404) - return true - } - ) - } - ) + ) + } ) return suite diff --git a/services/device/test/operations/devices/device/index.spec.ts b/services/device/test/operations/devices/device/index.spec.ts index b9a0bb96..f5308f51 100644 --- a/services/device/test/operations/devices/device/index.spec.ts +++ b/services/device/test/operations/devices/device/index.spec.ts @@ -1,6 +1,7 @@ +import availabilitySpec from './availability/index.spec' import deleteSpec from './delete.spec' import getSpec from './get.spec' import patchSpec from './patch.spec' import postSpec from './post.spec' -export default [deleteSpec, getSpec, patchSpec, postSpec] +export default [...availabilitySpec, deleteSpec, getSpec, patchSpec, postSpec] diff --git a/services/device/test/operations/devices/device/patch.spec.ts b/services/device/test/operations/devices/device/patch.spec.ts index 0d156162..93a3074b 100644 --- a/services/device/test/operations/devices/device/patch.spec.ts +++ b/services/device/test/operations/devices/device/patch.spec.ts @@ -16,6 +16,7 @@ import { instantiableBrowserDeviceNames } from '../../../data/devices/instantiab import { instantiableCloudDeviceNames } from '../../../data/devices/instantiableCloudDevices/index.spec' import { TestData } from '../../../data/index.spec' import { deviceRepositoryTestSuite } from '../../../database/repositories/device.spec' +import { addTest } from '../../index.spec' import { InvalidValueError, MissingEntityError } from '@crosslab/service-common' import assert from 'assert' import Mocha from 'mocha' @@ -23,6 +24,75 @@ import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('PATCH /devices/{device_id}', context) + suite.afterEach(function () { + changedCallbacks.clear() + }) + + suite.addSuite(buildDeviceSuite('cloud instantiable', testData)) + suite.addSuite(buildDeviceSuite('device', testData)) + suite.addSuite(buildDeviceSuite('edge instantiable', testData)) + suite.addSuite(buildDeviceSuite('group', testData)) + + addTest( + suite, + 'should throw a MissingEntityError if device is not found', + async function () { + await assert.rejects( + async () => { + await patchDevicesByDeviceId( + { device_id: 'non-existent' }, + { type: 'device' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert(error.status === 404) + return true + } + ) + } + ) + + addTest( + suite, + 'should register a device-changed callback url for the device if provided', + async function () { + for (const deviceName of deviceNames) { + const device = testData.devices[deviceName] + const changedUrl = 'http://localhost/callbacks' + + const result = await patchDevicesByDeviceId( + { device_id: device.model.uuid, changedUrl }, + undefined, + testData.userData + ) + + assert(result.status === 200) + assert( + deviceRepositoryTestSuite.validateWrite(device.model, device.request) + ) + const changedCallbackUrls = changedCallbacks.get(device.model.uuid) + assert(changedCallbackUrls) + assert(changedCallbackUrls.length === 1) + assert(changedCallbackUrls[0] === changedUrl) + } + } + ) + + return suite +} + +function getDeviceData( + type: 'device' | 'group' | 'edge instantiable' | 'cloud instantiable' +): { + body: DeviceUpdate + names: + | typeof instantiableBrowserDeviceNames + | typeof instantiableCloudDeviceNames + | typeof concreteDeviceNames + | typeof deviceGroupNames +} { const updatedName = 'new name' const updatedDescription = 'new description' const updatedServices: ServiceDescription[] = [ @@ -78,170 +148,94 @@ export default function (context: Mocha.Context, testData: TestData) { services: updatedServices, } - function getDeviceData( - type: 'device' | 'group' | 'edge instantiable' | 'cloud instantiable' - ): { - body: DeviceUpdate - names: - | typeof instantiableBrowserDeviceNames - | typeof instantiableCloudDeviceNames - | typeof concreteDeviceNames - | typeof deviceGroupNames - } { - switch (type) { - case 'cloud instantiable': - return { - body: instantiableCloudDeviceBody, - names: instantiableCloudDeviceNames, - } - case 'device': - return { - body: concreteDeviceBody, - names: concreteDeviceNames, - } - case 'edge instantiable': - return { - body: instantiableBrowserDeviceBody, - names: instantiableBrowserDeviceNames, - } - case 'group': - return { - body: deviceGroupBody, - names: deviceGroupNames, - } - } + switch (type) { + case 'cloud instantiable': + return { + body: instantiableCloudDeviceBody, + names: instantiableCloudDeviceNames, + } + case 'device': + return { + body: concreteDeviceBody, + names: concreteDeviceNames, + } + case 'edge instantiable': + return { + body: instantiableBrowserDeviceBody, + names: instantiableBrowserDeviceNames, + } + case 'group': + return { + body: deviceGroupBody, + names: deviceGroupNames, + } } +} - function buildDeviceSuite( - type: 'device' | 'group' | 'edge instantiable' | 'cloud instantiable' - ): Mocha.Suite { - return new Mocha.Suite(`device type '${type}'`) - .addTest( - new Mocha.Test( - `should update a device of type '${type}'`, - async function () { - const deviceData = getDeviceData(type) - for (const deviceName of deviceData.names) { - const device = testData['devices'][deviceName] - const result = await patchDevicesByDeviceId( - { device_id: device.model.uuid }, - deviceData.body, - testData.userData - ) - - assert(result.status === 200) - const updatedDeviceModel = - await deviceRepository.findOneOrFail({ - where: { - uuid: device.model.uuid, - }, - }) - assert( - deviceRepositoryTestSuite.validateWrite( - updatedDeviceModel, - deviceData.body - ) - ) - assert(changedCallbacks.get(device.model.uuid) === undefined) - } - } - ) +function buildDeviceSuite( + type: 'device' | 'group' | 'edge instantiable' | 'cloud instantiable', + testData: TestData +): Mocha.Suite { + const deviceSuite = new Mocha.Suite(`device type '${type}'`) + + addTest(deviceSuite, `should update a device of type '${type}'`, async function () { + const deviceData = getDeviceData(type) + for (const deviceName of deviceData.names) { + const device = testData['devices'][deviceName] + const result = await patchDevicesByDeviceId( + { device_id: device.model.uuid }, + deviceData.body, + testData.userData ) - .addTest( - new Mocha.Test( - `should throw an error if the type of the update is not '${type}'`, - async function () { - const deviceData = getDeviceData(type) - for (const deviceName of deviceData.names) { - const device = testData['devices'][deviceName] - for (const deviceType of [ - 'device', - 'group', - 'edge instantiable', - 'cloud instantiable', - ] as const) { - if (deviceType === type) continue - await assert.rejects( - async () => { - await patchDevicesByDeviceId( - { device_id: device.model.uuid }, - { type: deviceType }, - testData.userData - ) - }, - (error) => { - assert(error instanceof InvalidValueError) - assert(error.status === 400) - return true - } - ) - } - } - } + + assert(result.status === 200) + const updatedDeviceModel = await deviceRepository.findOneOrFail({ + where: { + uuid: device.model.uuid, + }, + }) + assert( + deviceRepositoryTestSuite.validateWrite( + updatedDeviceModel, + deviceData.body ) ) - } - - suite.afterEach(function () { - changedCallbacks.clear() + assert(changedCallbacks.get(device.model.uuid) === undefined) + } }) - suite.addSuite(buildDeviceSuite('cloud instantiable')) - suite.addSuite(buildDeviceSuite('device')) - suite.addSuite(buildDeviceSuite('edge instantiable')) - suite.addSuite(buildDeviceSuite('group')) - - suite.addTest( - new Mocha.Test( - 'should throw a MissingEntityError if device is not found', - async function () { - await assert.rejects( - async () => { - await patchDevicesByDeviceId( - { device_id: 'non-existent' }, - { type: 'device' }, - testData.userData - ) - }, - (error) => { - assert(error instanceof MissingEntityError) - assert(error.status === 404) - return true - } - ) - } - ) - ) - - suite.addTest( - new Mocha.Test( - 'should register a device-changed callback url for the device if provided', - async function () { - for (const deviceName of deviceNames) { - const device = testData.devices[deviceName] - const changedUrl = 'http://localhost/callbacks' - - const result = await patchDevicesByDeviceId( - { device_id: device.model.uuid, changedUrl }, - undefined, - testData.userData - ) - - assert(result.status === 200) - assert( - deviceRepositoryTestSuite.validateWrite( - device.model, - device.request - ) + addTest( + deviceSuite, + `should throw an error if the type of the update is not '${type}'`, + async function () { + const deviceData = getDeviceData(type) + for (const deviceName of deviceData.names) { + const device = testData['devices'][deviceName] + for (const deviceType of [ + 'device', + 'group', + 'edge instantiable', + 'cloud instantiable', + ] as const) { + if (deviceType === type) continue + await assert.rejects( + async () => { + await patchDevicesByDeviceId( + { device_id: device.model.uuid }, + { type: deviceType }, + testData.userData + ) + }, + (error) => { + assert(error instanceof InvalidValueError) + assert(error.status === 400) + return true + } ) - const changedCallbackUrls = changedCallbacks.get(device.model.uuid) - assert(changedCallbackUrls) - assert(changedCallbackUrls.length === 1) - assert(changedCallbackUrls[0] === changedUrl) } } - ) + } ) - return suite + return deviceSuite } diff --git a/services/device/test/operations/devices/device/post.spec.ts b/services/device/test/operations/devices/device/post.spec.ts index 8f3510b2..840c1c6b 100644 --- a/services/device/test/operations/devices/device/post.spec.ts +++ b/services/device/test/operations/devices/device/post.spec.ts @@ -1,11 +1,13 @@ import { concreteDeviceRepository } from '../../../../src/database/repositories/device/concreteDevice' import { ConcreteDevice } from '../../../../src/generated/types' import { apiClient } from '../../../../src/globals' +import { changedCallbacks } from '../../../../src/methods/callbacks' import { postDevicesByDeviceId } from '../../../../src/operations/devices' import { instantiableBrowserDeviceNames } from '../../../data/devices/instantiableBrowserDevices/index.spec' import { instantiableCloudDeviceNames } from '../../../data/devices/instantiableCloudDevices/index.spec' import { TestData } from '../../../data/index.spec' import { concreteDeviceRepositoryTestSuite } from '../../../database/repositories/device/concreteDevice.spec' +import { addTest } from '../../index.spec' import { ForbiddenOperationError, MissingEntityError } from '@crosslab/service-common' import assert from 'assert' import Mocha from 'mocha' @@ -55,55 +57,53 @@ export default function (context: Mocha.Context, testData: TestData) { createDeviceAuthenticationTokenStub.restore() }) - suite.addTest( - new Mocha.Test( - 'should throw a MissingEntityError if device is not found', - async function () { + addTest( + suite, + 'should throw a MissingEntityError if device is not found', + async function () { + await assert.rejects( + async () => { + await postDevicesByDeviceId( + { device_id: 'non-existent' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert(error.status === 404) + return true + } + ) + } + ) + + addTest( + suite, + 'should throw a ForbiddenOperationError if the device is not instantiable', + async function () { + const deviceModels = [ + testData['concrete devices']['concrete device'].model, + testData['device groups']['device group'].model, + ] + + for (const deviceModel of deviceModels) { await assert.rejects( async () => { await postDevicesByDeviceId( - { device_id: 'non-existent' }, + { + device_id: deviceModel.uuid, + }, testData.userData ) }, (error) => { - assert(error instanceof MissingEntityError) - assert(error.status === 404) + assert(error instanceof ForbiddenOperationError) + assert(error.status === 400) return true } ) } - ) - ) - - suite.addTest( - new Mocha.Test( - 'should throw a ForbiddenOperationError if the device is not instantiable', - async function () { - const deviceModels = [ - testData['concrete devices']['concrete device'].model, - testData['device groups']['device group'].model, - ] - - for (const deviceModel of deviceModels) { - await assert.rejects( - async () => { - await postDevicesByDeviceId( - { - device_id: deviceModel.uuid, - }, - testData.userData - ) - }, - (error) => { - assert(error instanceof ForbiddenOperationError) - assert(error.status === 400) - return true - } - ) - } - } - ) + } ) const instantiableDevices = { @@ -111,46 +111,84 @@ export default function (context: Mocha.Context, testData: TestData) { ...testData['instantiable cloud devices'], } - for (const instantiableDeviceName of [ + const instantiableDeviceNames = [ ...instantiableBrowserDeviceNames, ...instantiableCloudDeviceNames, - ]) { - suite.addTest( - new Mocha.Test( - `should successfully instantiate an instantiable device (${instantiableDeviceName})`, - async function () { - const deviceModel = instantiableDevices[instantiableDeviceName].model - - const result = await postDevicesByDeviceId( - { device_id: deviceModel.uuid }, - testData.userData - ) + ] - assert(result.status === 201) - assert(result.body.deviceToken === DEVICE_TOKEN) - const instanceModel = await concreteDeviceRepository.findOneOrFail({ - where: { uuid: INSTANCE_UUID }, - }) + for (const instantiableDeviceName of instantiableDeviceNames) { + addTest( + suite, + `should successfully instantiate an instantiable device (${instantiableDeviceName})`, + async function () { + const deviceModel = instantiableDevices[instantiableDeviceName].model - assert( - concreteDeviceRepositoryTestSuite.validateFormat( - instanceModel, - result.body.instance - ) + const result = await postDevicesByDeviceId( + { device_id: deviceModel.uuid }, + testData.userData + ) + + assert(result.status === 201) + assert(result.body.deviceToken === DEVICE_TOKEN) + const instanceModel = await concreteDeviceRepository.findOneOrFail({ + where: { uuid: INSTANCE_UUID }, + }) + + assert( + concreteDeviceRepositoryTestSuite.validateFormat( + instanceModel, + result.body.instance ) - } - ) + ) + + const instanceUUID = result.body.instance.url.split('/').at(-1) + assert(instanceUUID) + assert(!changedCallbacks.get(instanceUUID)) + } ) } - suite.addTest( - new Mocha.Test( - 'should register changed-callback for created instance', + for (const [index, instantiableDeviceName] of instantiableDeviceNames.entries()) { + addTest( + suite, + `should register changed-callback for created instance (${instantiableDeviceName})`, async function (this: Mocha.Context) { - this.skip() + const deviceModel = instantiableDevices[instantiableDeviceName].model + const changedUrl = `https://localhost/callbacks/${index}` + + const result = await postDevicesByDeviceId( + { device_id: deviceModel.uuid, changedUrl }, + testData.userData + ) + + assert(result.status === 201) + assert(result.body.deviceToken === DEVICE_TOKEN) + const instanceModel = await concreteDeviceRepository.findOneOrFail({ + where: { uuid: INSTANCE_UUID }, + }) + + assert( + concreteDeviceRepositoryTestSuite.validateFormat( + instanceModel, + result.body.instance + ) + ) + + const instanceUUID = result.body.instance.url.split('/').at(-1) + assert(instanceUUID) + + const registeredCallbackUrls = changedCallbacks.get(instanceUUID) + assert(registeredCallbackUrls) + assert(registeredCallbackUrls.length === index + 1) + + for (let i = 0; i <= index; i++) { + assert( + registeredCallbackUrls[i] === `https://localhost/callbacks/${i}` + ) + } } ) - ) + } return suite } diff --git a/services/device/test/operations/devices/get.spec.ts b/services/device/test/operations/devices/get.spec.ts index f44e7f82..6548b426 100644 --- a/services/device/test/operations/devices/get.spec.ts +++ b/services/device/test/operations/devices/get.spec.ts @@ -2,31 +2,30 @@ import { getDevices } from '../../../src/operations/devices' import { deviceNames } from '../../data/devices/index.spec' import { TestData } from '../../data/index.spec' import { DeviceOverviewRepositoryTestSuite } from '../../database/repositories/device/deviceOverview.spec' +import { addTest } from '../index.spec' import assert from 'assert' import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('GET /devices', context) - suite.addTest( - new Mocha.Test('should get all devices', async function () { - const result = await getDevices(testData.userData) - assert(result.status === 200) + addTest(suite, 'should get all devices', async function () { + const result = await getDevices(testData.userData) + assert(result.status === 200) - for (const deviceName of deviceNames) { - const searchedDevice = testData.devices[deviceName].response - assert( - result.body.find((device) => - DeviceOverviewRepositoryTestSuite.compareFormatted( - device, - searchedDevice - ) - ), - `could not find device '${deviceName}'` - ) - } - }) - ) + for (const deviceName of deviceNames) { + const searchedDevice = testData.devices[deviceName].response + assert( + result.body.find((device) => + DeviceOverviewRepositoryTestSuite.compareFormatted( + device, + searchedDevice + ) + ), + `could not find device '${deviceName}'` + ) + } + }) return suite } diff --git a/services/device/test/operations/devices/post.spec.ts b/services/device/test/operations/devices/post.spec.ts index 9be2bfa5..bfd875a6 100644 --- a/services/device/test/operations/devices/post.spec.ts +++ b/services/device/test/operations/devices/post.spec.ts @@ -5,6 +5,7 @@ import { postDevices } from '../../../src/operations/devices' import { deviceNames } from '../../data/devices/index.spec' import { TestData } from '../../data/index.spec' import { deviceRepositoryTestSuite } from '../../database/repositories/device.spec' +import { addTest } from '../index.spec' import { EntityData } from '@crosslab/service-common' import assert from 'assert' import Mocha from 'mocha' @@ -64,28 +65,22 @@ export default function (context: Mocha.Context, testData: TestData) { } for (const deviceName of deviceNames) { - suite.addTest( - new Mocha.Test( - `should create a new device (${deviceName})`, - async function () { - await createDevice(testData.devices[deviceName]) - } - ) - ) + addTest(suite, `should create a new device (${deviceName})`, async function () { + await createDevice(testData.devices[deviceName]) + }) } - suite.addTest( - new Mocha.Test( - 'should create a new device and register a callback url', - async function () { - for (const deviceName of deviceNames) { - createDevice( - testData.devices[deviceName], - `http://localhost/callbacks/${deviceName}` - ) - } + addTest( + suite, + 'should create a new device and register a callback url', + async function () { + for (const deviceName of deviceNames) { + createDevice( + testData.devices[deviceName], + `http://localhost/callbacks/${deviceName}` + ) } - ) + } ) return suite diff --git a/services/device/test/operations/index.spec.ts b/services/device/test/operations/index.spec.ts index 01cff7e0..2cb0cdd3 100644 --- a/services/device/test/operations/index.spec.ts +++ b/services/device/test/operations/index.spec.ts @@ -3,9 +3,18 @@ import { TestData } from '../data/index.spec' import { initTestDatabase } from '../database/repositories/index.spec' import deviceTests from './devices/index.spec' import peerconnectionTests from './peerconnections/index.spec' +import Mocha from 'mocha' const tests = [...deviceTests, ...peerconnectionTests] +export function addTest( + suite: Mocha.Suite, + name: string, + fn?: Mocha.Func | Mocha.AsyncFunc +) { + suite.addTest(new Mocha.Test(name, fn)) +} + describe('Operations', function () { let testData: TestData let suite: Mocha.Suite = this diff --git a/services/device/test/operations/peerconnections/get.spec.ts b/services/device/test/operations/peerconnections/get.spec.ts index 7531c4c6..60fd3904 100644 --- a/services/device/test/operations/peerconnections/get.spec.ts +++ b/services/device/test/operations/peerconnections/get.spec.ts @@ -2,31 +2,30 @@ import { getPeerconnections } from '../../../src/operations/peerconnections' import { TestData } from '../../data/index.spec' import { peerconnectionNames } from '../../data/peerconnections/index.spec' import { peerconnectionRepositoryTestSuite } from '../../database/repositories/peerconnection.spec' +import { addTest } from '../index.spec' import assert from 'assert' import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('GET /peerconnections', context) - suite.addTest( - new Mocha.Test('should get all peerconnections', async function () { - const result = await getPeerconnections(testData.userData) - assert(result.status === 200) + addTest(suite, 'should get all peerconnections', async function () { + const result = await getPeerconnections(testData.userData) + assert(result.status === 200) - for (const peerconnectionName of peerconnectionNames) { - const searchedPeerconnection = - testData.peerconnections[peerconnectionName].response - assert( - result.body.find((peerconnection) => - peerconnectionRepositoryTestSuite.compareFormatted( - peerconnection, - searchedPeerconnection - ) + for (const peerconnectionName of peerconnectionNames) { + const searchedPeerconnection = + testData.peerconnections[peerconnectionName].response + assert( + result.body.find((peerconnection) => + peerconnectionRepositoryTestSuite.compareFormatted( + peerconnection, + searchedPeerconnection ) ) - } - }) - ) + ) + } + }) return suite } From 0e4655a1fc2e2de22ecd34e01653f583ab87764d Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Fri, 21 Apr 2023 15:43:44 +0200 Subject: [PATCH 26/33] Change index.ts to function and add callback tests --- services/device/src/index.ts | 92 ++++--- services/device/src/methods/availability.ts | 32 +-- .../callbacks/event/deviceChanged.ts | 21 +- .../src/operations/callbacks/event/index.ts | 4 +- .../device/src/operations/callbacks/index.ts | 44 ++- .../callbacks/event/deviceChanged.spec.ts | 260 ++++++++++++++++++ .../operations/callbacks/event/index.spec.ts | 104 +++++++ .../test/operations/callbacks/index.spec.ts | 148 ++++++++++ services/device/test/operations/index.spec.ts | 3 +- 9 files changed, 613 insertions(+), 95 deletions(-) diff --git a/services/device/src/index.ts b/services/device/src/index.ts index da70a72c..abefe337 100644 --- a/services/device/src/index.ts +++ b/services/device/src/index.ts @@ -19,51 +19,57 @@ declare global { } } -AppDataSource.initialize(dataSourceConfig) - .then(() => { - app.use((req, _res, next) => { - for (const param in req.query) { - if (typeof req.query[param] == 'string') { - if (req.query[param] == 'true') { - ;(req.query[param] as any) = true - } else if (req.query[param] == 'false') { - ;(req.query[param] as any) = false - } else if (req.query[param] == 'undefined') { - ;(req.query[param] as any) = undefined - } - } - } - next() - }) +async function startDeviceService() { + await AppDataSource.initialize(dataSourceConfig) - app.get('/device/status', (_req, res) => { - res.send({ status: 'ok' }) - }); - - app.initService({ - security: { - JWT: JWTVerify(config) as any, - }, - additionalHandlers: [callbackHandling], - }) - const wsServer = new WebSocket.Server({ noServer: true }) - app.wsListeners = new Map() - app.ws = (path, listener) => app.wsListeners.set(path, listener) - websocketHandling(app) - const server = app.listen(config.PORT) - server.on( - 'upgrade', - async (request: IncomingMessage, socket: Socket, head: Buffer) => { - const listener = app.wsListeners.get(request.url ?? '') - if (listener) { - wsServer.handleUpgrade(request, socket, head, (socket) => - listener(socket) - ) + app.use((req, _res, next) => { + for (const param in req.query) { + if (typeof req.query[param] === 'string') { + if (req.query[param] === 'true') { + ;(req.query[param] as any) = true + } else if (req.query[param] === 'false') { + ;(req.query[param] as any) = false + } else if (req.query[param] === 'undefined') { + ;(req.query[param] as any) = undefined } } - ) - console.log('Device Service started successfully') + } + next() }) - .catch((err) => { - console.error('Error during Data Source initialization:', err) + + app.get('/device/status', (_req, res) => { + res.send({ status: 'ok' }) + }) + + app.initService({ + security: { + JWT: JWTVerify(config) as any, + }, + additionalHandlers: [callbackHandling], }) + + const wsServer = new WebSocket.Server({ noServer: true }) + app.wsListeners = new Map() + app.ws = (path, listener) => app.wsListeners.set(path, listener) + websocketHandling(app) + + const server = app.listen(config.PORT) + server.on( + 'upgrade', + async (request: IncomingMessage, socket: Socket, head: Buffer) => { + const listener = app.wsListeners.get(request.url ?? '') + if (listener) { + wsServer.handleUpgrade(request, socket, head, (socket) => + listener(socket) + ) + } + } + ) + + console.log('Device Service started successfully') +} + +/* istanbul ignore if */ +if (require.main === module) { + startDeviceService() +} diff --git a/services/device/src/methods/availability.ts b/services/device/src/methods/availability.ts index ee52f83a..2e3ccafc 100644 --- a/services/device/src/methods/availability.ts +++ b/services/device/src/methods/availability.ts @@ -62,7 +62,7 @@ function applyAvailabilityRule( end: number ) { if (availabilityRule.available === true || availabilityRule.available === undefined) { - console.log('applying availability rule for available = true') + // console.log('applying availability rule for available = true') // add all new timeslots availability = addTimeSlotsFromRule(availability, availabilityRule, start, end) @@ -73,7 +73,7 @@ function applyAvailabilityRule( // merge timeslots availability = mergeOverlappingTimeSlots(availability) } else { - console.log('applying availability rule for available = false') + // console.log('applying availability rule for available = false') // invert availability availability = invertTimeSlots(availability, start, end) @@ -107,10 +107,10 @@ function addTimeSlotsFromRule( start: number, end: number ) { - console.log( - 'availability before adding timeslots from rule:', - JSON.stringify(availability, null, 4) - ) + // console.log( + // 'availability before adding timeslots from rule:', + // JSON.stringify(availability, null, 4) + // ) const timeSlot: TimeSlotModel = { start: availabilityRule.start || start, end: availabilityRule.end || end, @@ -154,10 +154,10 @@ function addTimeSlotsFromRule( availability.push(timeSlot) - console.log( - 'availability after adding timeslots from rule:', - JSON.stringify(availability, null, 4) - ) + // console.log( + // 'availability after adding timeslots from rule:', + // JSON.stringify(availability, null, 4) + // ) return availability .map((ts) => { return { @@ -177,13 +177,13 @@ function addTimeSlotsFromRule( * @returns The sorted list of timeslots. */ function sortTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { - console.log('availability before sort:', JSON.stringify(availability, null, 4)) + // console.log('availability before sort:', JSON.stringify(availability, null, 4)) availability.sort((a, b) => { if (a.start < b.start) return -1 if (a.start > b.start) return 1 return 0 }) - console.log('availability after sort:', JSON.stringify(availability, null, 4)) + // console.log('availability after sort:', JSON.stringify(availability, null, 4)) return availability } @@ -193,7 +193,7 @@ function sortTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { * @returns The list of timeslots with no overlap. */ function mergeOverlappingTimeSlots(availability: TimeSlotModel[]): TimeSlotModel[] { - console.log('availability before merge:', JSON.stringify(availability, null, 4)) + // console.log('availability before merge:', JSON.stringify(availability, null, 4)) const mergedAvailability: TimeSlotModel[] = [] let currentIndex = 0 @@ -214,7 +214,7 @@ function mergeOverlappingTimeSlots(availability: TimeSlotModel[]): TimeSlotModel } } } - console.log('availability after merge:', JSON.stringify(mergedAvailability, null, 4)) + // console.log('availability after merge:', JSON.stringify(mergedAvailability, null, 4)) return mergedAvailability } @@ -231,7 +231,7 @@ function invertTimeSlots( end: number ): TimeSlotModel[] { if (availability.length === 0) return [] - console.log('availability before invert:', JSON.stringify(availability, null, 4)) + // console.log('availability before invert:', JSON.stringify(availability, null, 4)) // sort by starttime availability = sortTimeSlots(availability) @@ -269,6 +269,6 @@ function invertTimeSlots( if (lastTimeSlot.start !== lastTimeSlot.end) newAvailability.push(lastTimeSlot) availability = newAvailability - console.log('availability after invert:', JSON.stringify(availability, null, 4)) + // console.log('availability after invert:', JSON.stringify(availability, null, 4)) return availability } diff --git a/services/device/src/operations/callbacks/event/deviceChanged.ts b/services/device/src/operations/callbacks/event/deviceChanged.ts index fd85adda..00cd5480 100644 --- a/services/device/src/operations/callbacks/event/deviceChanged.ts +++ b/services/device/src/operations/callbacks/event/deviceChanged.ts @@ -29,26 +29,22 @@ export async function handleDeviceChangedEventCallback(callback: { const device = callback.device if ( - !isConcreteDevice(device) && - !isDeviceGroup(device) && - !isInstantiableBrowserDevice(device) && - !isInstantiableCloudDevice(device) + !isConcreteDevice(device, 'response') && + !isDeviceGroup(device, 'response') && + !isInstantiableBrowserDevice(device, 'response') && + !isInstantiableCloudDevice(device, 'response') ) { throw new MalformedBodyError('Property "device" is not a valid device', 400) } - if (!device.url) { - throw new MalformedBodyError('Property "device" is missing url', 400) - } - - if (isConcreteDevice(device)) { + if (isConcreteDevice(device, 'response')) { return await handleConcreteDevice(device) } else { return 410 } } -async function handleConcreteDevice(concreteDevice: ConcreteDevice) { +async function handleConcreteDevice(concreteDevice: ConcreteDevice<'response'>) { const pendingConnectionsA = await peerconnectionRepository.find({ where: { status: 'connecting', @@ -67,7 +63,10 @@ async function handleConcreteDevice(concreteDevice: ConcreteDevice) { }, }) - const pendingConnections = [...pendingConnectionsA, ...pendingConnectionsB] + const pendingConnections = [...pendingConnectionsA, ...pendingConnectionsB].filter( + (peerconnection, index, array) => + array.findIndex((pc) => pc.uuid === peerconnection.uuid) === index + ) for (const pendingConnection of pendingConnections) { const deviceA = await apiClient.getDevice(pendingConnection.deviceA.url) diff --git a/services/device/src/operations/callbacks/event/index.ts b/services/device/src/operations/callbacks/event/index.ts index f45f5843..8519f4df 100644 --- a/services/device/src/operations/callbacks/event/index.ts +++ b/services/device/src/operations/callbacks/event/index.ts @@ -17,12 +17,14 @@ export async function handleEventCallback(callback: { 400 ) } + if (typeof callback.eventType !== 'string') { throw new MalformedBodyError( - "Property 'callbackType' needs to be of type 'string'", + "Property 'eventType' needs to be of type 'string'", 400 ) } + switch (callback.eventType) { case 'device-changed': return await handleDeviceChangedEventCallback(callback) diff --git a/services/device/src/operations/callbacks/index.ts b/services/device/src/operations/callbacks/index.ts index 06e305af..e7823e32 100644 --- a/services/device/src/operations/callbacks/index.ts +++ b/services/device/src/operations/callbacks/index.ts @@ -5,18 +5,35 @@ import express from 'express' export * from '../../methods/callbacks' /** - * This function adds the endpoint for incoming callbacks registered by the peerconnection service. + * This function adds the endpoint for incoming callbacks registered by the device service. * @param app The express application the callback endpoint should be added to. */ export function callbackHandling(app: express.Application) { app.post('/callbacks/device', async (req, res, next) => { try { - const callback: any = req.body + const callback: unknown = req.body + if (typeof callback !== 'object') throw new MalformedBodyError('Body of callback is not an object', 400) - const callbackType = getCallbackType(callback) - switch (callbackType) { + if (callback === null) + throw new MalformedBodyError('Body of callback is null', 400) + + if (!('callbackType' in callback)) { + throw new MalformedBodyError( + "Callbacks require property 'callbackType'", + 400 + ) + } + + if (typeof callback.callbackType !== 'string') { + throw new MalformedBodyError( + "Property 'callbackType' needs to be of type string", + 400 + ) + } + + switch (callback.callbackType) { case 'event': return res.status(await handleEventCallback(callback)).send() default: @@ -30,22 +47,3 @@ export function callbackHandling(app: express.Application) { } }) } - -/** - * This function attempts to get the type of an incoming callback. - * @param callback The incoming callback of which to get the type. - * @throws {MalformedBodyError} Thrown if the callback is malformed. - * @returns The type of the incoming callback. - */ -function getCallbackType(callback: any) { - if (typeof callback.callbackType !== 'string') { - throw new MalformedBodyError( - "Property 'callbackType' needs to be of type string", - 400 - ) - } - if (!callback.callbackType) { - throw new MalformedBodyError("Callbacks require property 'callbackType'", 400) - } - return callback.callbackType as string -} diff --git a/services/device/test/operations/callbacks/event/deviceChanged.spec.ts b/services/device/test/operations/callbacks/event/deviceChanged.spec.ts index e69de29b..45e7cd7e 100644 --- a/services/device/test/operations/callbacks/event/deviceChanged.spec.ts +++ b/services/device/test/operations/callbacks/event/deviceChanged.spec.ts @@ -0,0 +1,260 @@ +import { PeerconnectionModel } from '../../../../src/database/model' +import { peerconnectionRepository } from '../../../../src/database/repositories/peerconnection' +import { apiClient, timeoutMap } from '../../../../src/globals' +import { signalingQueue } from '../../../../src/methods/signaling' +import { handleDeviceChangedEventCallback } from '../../../../src/operations/callbacks/event/deviceChanged' +import { TestData } from '../../../data/index.spec' +import { addTest } from '../../index.spec' +import { MalformedBodyError } from '@crosslab/service-common' +import assert from 'assert' +import Mocha from 'mocha' +import rewire from 'rewire' +import * as sinon from 'sinon' + +export function deviceChangedEventCallbackTest( + context: Mocha.Context, + testData: TestData +) { + const suite = new Mocha.Suite('device-changed event-callback handling', context) + + addTest( + suite, + "should throw a MalformedBodyError if body of callback does not contain property 'device'", + async function () { + await assert.rejects( + async () => { + await handleDeviceChangedEventCallback({}) + }, + (error) => { + assert(error instanceof MalformedBodyError) + assert.strictEqual(error.status, 400) + assert.strictEqual( + error.message, + "Event-callbacks of type 'device-changed' require property 'device'" + ) + return true + } + ) + } + ) + + addTest( + suite, + "should throw a MalformedBodyError if property 'device' in body of callback is not a valid device", + async function () { + await assert.rejects( + async () => { + await handleDeviceChangedEventCallback({ device: 'invalid' }) + }, + (error) => { + assert(error instanceof MalformedBodyError) + assert.strictEqual(error.status, 400), + assert.strictEqual( + error.message, + 'Property "device" is not a valid device' + ) + return true + } + ) + } + ) + + addTest( + suite, + "should return 410 if the device is not of type 'device'", + async function () { + const devices = [ + testData['instantiable browser devices']['instantiable browser device'] + .response, + testData['instantiable cloud devices']['instantiable cloud device'] + .response, + testData['device groups']['device group'].response, + ] + + for (const device of devices) { + const result = await handleDeviceChangedEventCallback({ + device, + }) + + assert.strictEqual(result, 410) + } + } + ) + + addTest( + suite, + "should call the correct function for a device of type 'device'", + async () => { + const handleConcreteDeviceStub = sinon.stub().resolves(200) + + const deviceChangedEventCallbackModule = rewire( + '../../../../src/operations/callbacks/event/deviceChanged.ts' + ) + + const handleDeviceChangedEventCallback = + deviceChangedEventCallbackModule.__get__( + 'handleDeviceChangedEventCallback' + ) + + await deviceChangedEventCallbackModule.__with__({ + handleConcreteDevice: handleConcreteDeviceStub, + })(async () => { + const result = await handleDeviceChangedEventCallback({ + device: testData['concrete devices']['concrete device'].response, + }) + + assert.strictEqual(result, 200) + assert(handleConcreteDeviceStub.calledOnce) + }) + } + ) + + addTest( + suite, + "should handle a device of type 'device' correctly (both connected and remaining connections)", + async () => { + const UUID_PEERCONNECTION = '9daf4e96-9ed7-4a1e-99d1-0a47371f8524' + const URL_DEVICE_A = + 'https://localhost/devices/e961ba8b-9b8f-4f96-b943-23212c8d4aa7' + const URL_DEVICE_B = + 'https://localhost/devices/879cca1d-ff3d-4374-bda2-188a2a607659' + const TIMEOUT = setTimeout(() => undefined, 100000) + const PEERCONNECTION_MODEL: PeerconnectionModel = { + uuid: UUID_PEERCONNECTION, + type: 'webrtc', + status: 'connecting', + deviceA: { + url: URL_DEVICE_A, + status: 'connecting', + }, + deviceB: { + url: URL_DEVICE_B, + status: 'connecting', + }, + } + + const peerconnectionRepositoryFindStub = sinon.stub( + peerconnectionRepository, + 'find' + ) + peerconnectionRepositoryFindStub.resolves([PEERCONNECTION_MODEL]) + + const getDeviceStub = sinon.stub(apiClient, 'getDevice') + getDeviceStub.callsFake(async (url, _options) => { + return { + type: 'device', + url: url, + name: 'Device', + owner: 'https://localhost/users/superadmin', + connected: true, + } + }) + + const addPeerconnectionStub = sinon.stub(signalingQueue, 'addPeerconnection') + + timeoutMap.set(UUID_PEERCONNECTION, TIMEOUT) + + const deviceChangedEventCallbackModule = rewire( + '../../../../src/operations/callbacks/event/deviceChanged.ts' + ) + + const handleConcreteDevice = + deviceChangedEventCallbackModule.__get__('handleConcreteDevice') + + const result = await handleConcreteDevice( + testData.devices['concrete device'].response + ) + + peerconnectionRepositoryFindStub.restore() + getDeviceStub.restore() + addPeerconnectionStub.restore() + assert(getDeviceStub.calledTwice) + assert.strictEqual(getDeviceStub.args[0][0], URL_DEVICE_A) + assert.strictEqual(getDeviceStub.args[1][0], URL_DEVICE_B) + assert(addPeerconnectionStub.calledOnce) + assert.strictEqual(addPeerconnectionStub.args[0][0], PEERCONNECTION_MODEL) + assert(!timeoutMap.get(UUID_PEERCONNECTION)) + assert((TIMEOUT as any)._destroyed) + assert.strictEqual(result, 200) + } + ) + + addTest( + suite, + "should handle a device of type 'device' correctly (both devices not connected and remaining connections)", + async () => { + const peerconnectionRepositoryFindStub = sinon.stub( + peerconnectionRepository, + 'find' + ) + peerconnectionRepositoryFindStub.resolves([ + { + uuid: '9daf4e96-9ed7-4a1e-99d1-0a47371f8524', + type: 'webrtc', + status: 'connecting', + deviceA: { + url: 'https://localhost/devices/e961ba8b-9b8f-4f96-b943-23212c8d4aa7', + status: 'connecting', + }, + deviceB: { + url: 'https://localhost/devices/879cca1d-ff3d-4374-bda2-188a2a607659', + status: 'connecting', + }, + }, + ]) + + const getDeviceStub = sinon.stub(apiClient, 'getDevice') + getDeviceStub.callsFake(async (url, _options) => { + return { + type: 'device', + url: url, + name: 'Device', + owner: 'https://localhost/users/superadmin', + connected: false, + } + }) + + const deviceChangedEventCallbackModule = rewire( + '../../../../src/operations/callbacks/event/deviceChanged.ts' + ) + + const handleConcreteDevice = + deviceChangedEventCallbackModule.__get__('handleConcreteDevice') + + const result = await handleConcreteDevice( + testData.devices['concrete device'].response + ) + + peerconnectionRepositoryFindStub.restore() + getDeviceStub.restore() + assert.strictEqual(result, 200) + } + ) + + addTest( + suite, + "should handle a device of type 'device' correctly (no remaining connections)", + async () => { + const peerconnectionRepositoryFindStub = sinon.stub( + peerconnectionRepository, + 'find' + ) + peerconnectionRepositoryFindStub.resolves([]) + + const deviceChangedEventCallbackModule = rewire( + '../../../../src/operations/callbacks/event/deviceChanged.ts' + ) + + const handleConcreteDevice = + deviceChangedEventCallbackModule.__get__('handleConcreteDevice') + + const result = await handleConcreteDevice( + testData.devices['concrete device'].response + ) + + assert.strictEqual(result, 410) + } + ) + + return suite +} diff --git a/services/device/test/operations/callbacks/event/index.spec.ts b/services/device/test/operations/callbacks/event/index.spec.ts index e69de29b..10e11e41 100644 --- a/services/device/test/operations/callbacks/event/index.spec.ts +++ b/services/device/test/operations/callbacks/event/index.spec.ts @@ -0,0 +1,104 @@ +import { handleEventCallback } from '../../../../src/operations/callbacks/event' +import * as deviceChangedEventCallbackHandling from '../../../../src/operations/callbacks/event/deviceChanged' +import { TestData } from '../../../data/index.spec' +import { addTest } from '../../index.spec' +import { deviceChangedEventCallbackTest } from './deviceChanged.spec' +import { InvalidValueError, MalformedBodyError } from '@crosslab/service-common' +import assert from 'assert' +import Mocha from 'mocha' +import * as sinon from 'sinon' + +export function eventCallbackTest(context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('event-callback handling', context) + + addTest( + suite, + "should throw a MalformedBodyError if body of callback does not contain property 'eventType'", + async function () { + await assert.rejects( + async () => { + await handleEventCallback({}) + }, + (error) => { + assert(error instanceof MalformedBodyError) + assert.strictEqual(error.status, 400) + assert.strictEqual( + error.message, + "Callbacks of type 'event' require property 'eventType'" + ) + return true + } + ) + } + ) + + addTest( + suite, + "should throw a MalformedBodyError if property 'eventType' in body of callback is not a string", + async function () { + await assert.rejects( + async () => { + await handleEventCallback({ eventType: 1 }) + }, + (error) => { + assert(error instanceof MalformedBodyError) + assert.strictEqual(error.status, 400) + assert.strictEqual( + error.message, + "Property 'eventType' needs to be of type 'string'" + ) + return true + } + ) + } + ) + + addTest( + suite, + 'should throw an InvalidValueError if the type of the event-callback is not supported', + async function () { + await assert.rejects( + async () => { + await handleEventCallback({ eventType: 'unsupported' }) + }, + (error) => { + assert(error instanceof InvalidValueError) + assert.strictEqual(error.status, 400) + assert.strictEqual( + error.message, + "Event-callbacks of type 'unsupported' are not supported" + ) + return true + } + ) + } + ) + + addTest( + suite, + "should call the correct function for a 'device-changed' event-callback", + async function () { + const handleDeviceChangedEventCallbackStub = sinon.stub( + deviceChangedEventCallbackHandling, + 'handleDeviceChangedEventCallback' + ) + handleDeviceChangedEventCallbackStub.resolves(200) + + try { + const result = await handleEventCallback({ eventType: 'device-changed' }) + + assert.strictEqual(result, 200) + assert(handleDeviceChangedEventCallbackStub.calledOnce) + + handleDeviceChangedEventCallbackStub.restore() + } catch (error) { + handleDeviceChangedEventCallbackStub.restore() + throw error + } + } + ) + + suite.addSuite(deviceChangedEventCallbackTest(suite.ctx, testData)) + + return suite +} diff --git a/services/device/test/operations/callbacks/index.spec.ts b/services/device/test/operations/callbacks/index.spec.ts index e69de29b..a5c1c5ed 100644 --- a/services/device/test/operations/callbacks/index.spec.ts +++ b/services/device/test/operations/callbacks/index.spec.ts @@ -0,0 +1,148 @@ +import { app } from '../../../src/generated' +import { callbackHandling } from '../../../src/operations/callbacks' +import * as eventCallbackHandling from '../../../src/operations/callbacks/event' +import { TestData } from '../../data/index.spec' +import { addTest } from '../index.spec' +import { eventCallbackTest } from './event/index.spec' +import { InvalidValueError, MalformedBodyError } from '@crosslab/service-common' +import assert from 'assert' +import express from 'express' +import Mocha from 'mocha' +import * as sinon from 'sinon' +import supertest from 'supertest' + +export default function (context: Mocha.Context, testData: TestData) { + const suite = new Mocha.Suite('callback handling', context) + + suite.beforeAll(function () { + app.initService({ + security: { + JWT: () => { + return { + url: 'https://localhost/users/test', + username: 'test', + scopes: [], + } + }, + }, + additionalHandlers: [ + (app: express.Application) => { + app.use((req, _res, next) => { + if ('content' in req.body) { + req.body = req.body.content + } + next() + }) + }, + callbackHandling, + ], + }) + }) + + addTest( + suite, + 'should return a MalformedBodyError if body of callback is not an object', + async function () { + const res = await supertest(app) + .post('/callbacks/device') + .send({ content: 'test' }) + + assert.strictEqual(res.status, 400) + assert.strictEqual(res.body.error, MalformedBodyError.name) + assert.strictEqual(res.body.message, 'Body of callback is not an object') + } + ) + + addTest( + suite, + 'should return a MalformedBodyError if body of callback is null', + async function () { + const res = await supertest(app) + .post('/callbacks/device') + .send({ content: null }) + + assert.strictEqual(res.status, 400) + assert.strictEqual(res.body.error, MalformedBodyError.name) + assert.strictEqual(res.body.message, 'Body of callback is null') + } + ) + + addTest( + suite, + "should return a MalformedBodyError if body of callback does not have property 'callbackType'", + async function () { + const res = await supertest(app).post('/callbacks/device').send({}) + + assert.strictEqual(res.status, 400) + assert.strictEqual(res.body.error, MalformedBodyError.name) + assert.strictEqual( + res.body.message, + "Callbacks require property 'callbackType'" + ) + } + ) + + addTest( + suite, + "should return a MalformedBodyError if property 'callbackType' in body of callback is not a string", + async function () { + const res = await supertest(app) + .post('/callbacks/device') + .send({ callbackType: 1 }) + + assert.strictEqual(res.status, 400) + assert.strictEqual(res.body.error, MalformedBodyError.name) + assert.strictEqual( + res.body.message, + "Property 'callbackType' needs to be of type string" + ) + } + ) + + addTest( + suite, + "should return a InvalidValueError if value of 'callbackType' in body of callback is not supported", + async function () { + const res = await supertest(app) + .post('/callbacks/device') + .send({ callbackType: 'unsupported' }) + + assert.strictEqual(res.status, 400) + assert.strictEqual(res.body.error, InvalidValueError.name) + assert.strictEqual( + res.body.message, + `Callbacks of type 'unsupported' are not supported` + ) + } + ) + + addTest( + suite, + "should call correct function for callback of type 'event'", + async function () { + const handleEventCallbackStub = sinon.stub( + eventCallbackHandling, + 'handleEventCallback' + ) + handleEventCallbackStub.resolves(200) + + try { + const res = await supertest(app) + .post('/callbacks/device') + .send({ callbackType: 'event' }) + + assert.strictEqual(res.status, 200) + assert(handleEventCallbackStub.calledOnce) + + handleEventCallbackStub.restore() + } catch (error) { + handleEventCallbackStub.restore() + throw error + } + } + ) + + suite.addSuite(eventCallbackTest(suite.ctx, testData)) + + return suite +} diff --git a/services/device/test/operations/index.spec.ts b/services/device/test/operations/index.spec.ts index 2cb0cdd3..be4e77ee 100644 --- a/services/device/test/operations/index.spec.ts +++ b/services/device/test/operations/index.spec.ts @@ -1,11 +1,12 @@ import { AppDataSource } from '../../src/database/dataSource' import { TestData } from '../data/index.spec' import { initTestDatabase } from '../database/repositories/index.spec' +import callbackTest from './callbacks/index.spec' import deviceTests from './devices/index.spec' import peerconnectionTests from './peerconnections/index.spec' import Mocha from 'mocha' -const tests = [...deviceTests, ...peerconnectionTests] +const tests = [...deviceTests, ...peerconnectionTests, callbackTest] export function addTest( suite: Mocha.Suite, From db33361bc67f6dbb6b47ae5232c52f987293625e Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 24 Apr 2023 16:08:21 +0200 Subject: [PATCH 27/33] Add more testcases --- services/device/src/methods/callbacks.ts | 108 ++++---- .../devices/device/websocket/post.ts | 22 +- .../peerconnections/peerconnection/delete.ts | 36 ++- .../peerconnection/device_status/patch.ts | 17 +- .../devices/device/availability/post.spec.ts | 2 - .../operations/devices/device/index.spec.ts | 12 +- .../devices/device/signaling/post.spec.ts | 164 ++++++++++++ .../devices/device/websocket/post.spec.ts | 98 +++++++ .../operations/peerconnections/index.spec.ts | 3 +- .../peerconnection/delete.spec.ts | 92 +++++++ .../device_status/patch.spec.ts | 239 ++++++++++++++++++ .../peerconnection/get.spec.ts | 47 ++++ .../peerconnection/index.spec.ts | 3 +- 13 files changed, 759 insertions(+), 84 deletions(-) diff --git a/services/device/src/methods/callbacks.ts b/services/device/src/methods/callbacks.ts index 062ad7c6..43c0f31d 100644 --- a/services/device/src/methods/callbacks.ts +++ b/services/device/src/methods/callbacks.ts @@ -26,23 +26,27 @@ export async function sendChangedCallback(device: DeviceModel) { )}' to '${url}'` ) - // TODO: error handling - const res = await fetch(url, { - method: 'POST', - body: JSON.stringify({ - callbackType: 'event', - eventType: 'device-changed', - device: await deviceRepository.format(device), - }), - headers: [['Content-Type', 'application/json']], - }) + // TODO: proper error handling + try { + const res = await fetch(url, { + method: 'POST', + body: JSON.stringify({ + callbackType: 'event', + eventType: 'device-changed', + device: await deviceRepository.format(device), + }), + headers: [['Content-Type', 'application/json']], + }) - if (res.status === 410) { - const changedCallbackURLs = changedCallbacks.get(device.uuid) - changedCallbacks.set( - device.uuid, - changedCallbackURLs?.filter((cb_url) => cb_url != url) - ) + if (res.status === 410) { + const changedCallbackURLs = changedCallbacks.get(device.uuid) + changedCallbacks.set( + device.uuid, + changedCallbackURLs?.filter((cb_url) => cb_url != url) + ) + } + } catch (error) { + console.error(error) } } } @@ -60,23 +64,27 @@ export async function sendClosedCallback(peerconnection: PeerconnectionModel) { )}' to '${url}'` ) - // TODO: error handling - const res = await fetch(url, { - method: 'POST', - body: JSON.stringify({ - callbackType: 'event', - eventType: 'peerconnection-closed', - peerconnection: await peerconnectionRepository.format(peerconnection), - }), - headers: [['Content-Type', 'application/json']], - }) + // TODO: proper error handling + try { + const res = await fetch(url, { + method: 'POST', + body: JSON.stringify({ + callbackType: 'event', + eventType: 'peerconnection-closed', + peerconnection: await peerconnectionRepository.format(peerconnection), + }), + headers: [['Content-Type', 'application/json']], + }) - if (res.status === 410) { - const closedCallbackURLs = closedCallbacks.get(peerconnection.uuid) - closedCallbacks.set( - peerconnection.uuid, - closedCallbackURLs?.filter((cb_url) => cb_url != url) - ) + if (res.status === 410) { + const closedCallbackURLs = closedCallbacks.get(peerconnection.uuid) + closedCallbacks.set( + peerconnection.uuid, + closedCallbackURLs?.filter((cb_url) => cb_url != url) + ) + } + } catch (error) { + console.error(error) } } } @@ -94,23 +102,27 @@ export async function sendStatusChangedCallback(peerconnection: PeerconnectionMo )}' to '${url}'` ) - // TODO: error handling - const res = await fetch(url, { - method: 'POST', - body: JSON.stringify({ - callbackType: 'event', - eventType: 'peerconnection-status-changed', - peerconnection: await peerconnectionRepository.format(peerconnection), - }), - headers: [['Content-Type', 'application/json']], - }) + // TODO: proper error handling + try { + const res = await fetch(url, { + method: 'POST', + body: JSON.stringify({ + callbackType: 'event', + eventType: 'peerconnection-status-changed', + peerconnection: await peerconnectionRepository.format(peerconnection), + }), + headers: [['Content-Type', 'application/json']], + }) - if (res.status === 410) { - const statusCallbackURLs = statusChangedCallbacks.get(peerconnection.uuid) - statusChangedCallbacks.set( - peerconnection.uuid, - statusCallbackURLs?.filter((cb_url) => cb_url != url) - ) + if (res.status === 410) { + const statusCallbackURLs = statusChangedCallbacks.get(peerconnection.uuid) + statusChangedCallbacks.set( + peerconnection.uuid, + statusCallbackURLs?.filter((cb_url) => cb_url != url) + ) + } + } catch (error) { + console.error(error) } } } diff --git a/services/device/src/operations/devices/device/websocket/post.ts b/services/device/src/operations/devices/device/websocket/post.ts index 509518ae..665c5e61 100644 --- a/services/device/src/operations/devices/device/websocket/post.ts +++ b/services/device/src/operations/devices/device/websocket/post.ts @@ -1,23 +1,33 @@ -import { AppDataSource } from '../../../../database/dataSource' -import { ConcreteDeviceModel } from '../../../../database/model' +import { deviceRepository } from '../../../../database/repositories/device' import { postDevicesByDeviceIdWebsocketSignature } from '../../../../generated/signatures' +import { + ForbiddenOperationError, + MissingEntityError as _MissingEntityError, +} from '@crosslab/service-common' import { randomUUID } from 'crypto' /** * This function implements the functionality for handling POST requests on /devices/{device_id}/token endpoint. * @param parameters The parameters of the request. * @param _user The user submitting the request. - * @throws {MissingEntityError} Thrown if device is not found in the database. + * @throws {_MissingEntityError} Thrown if device is not found in the database. */ export const postDevicesByDeviceIdWebsocket: postDevicesByDeviceIdWebsocketSignature = async (parameters, _user) => { console.log(`postDevicesByDeviceIdWebsocket called`) - const deviceRepository = AppDataSource.getRepository(ConcreteDeviceModel) - const deviceModel = await deviceRepository.findOneByOrFail({ - uuid: parameters.device_id, + const deviceModel = await deviceRepository.findOneOrFail({ + where: { + uuid: parameters.device_id, + }, }) + if (deviceModel.type !== 'device') + throw new ForbiddenOperationError( + "A websocket token may only be requested for a device of type 'device'", + 400 + ) + deviceModel.token = randomUUID() await deviceRepository.save(deviceModel) diff --git a/services/device/src/operations/peerconnections/peerconnection/delete.ts b/services/device/src/operations/peerconnections/peerconnection/delete.ts index abbe53db..32ca3048 100644 --- a/services/device/src/operations/peerconnections/peerconnection/delete.ts +++ b/services/device/src/operations/peerconnections/peerconnection/delete.ts @@ -14,42 +14,40 @@ export const deletePeerconnectionsByPeerconnectionId: deletePeerconnectionsByPee async (parameters, _user) => { console.log(`deletePeerconnectionsByPeerconnectionId called`) - const peerconnectionModel = await peerconnectionRepository.findOne({ + const peerconnectionModel = await peerconnectionRepository.findOneOrFail({ where: { uuid: parameters.peerconnection_id }, }) - if (!peerconnectionModel) - return { - status: 204, - } - - if ( - peerconnectionModel.status === 'connecting' || - peerconnectionModel.status === 'connected' || - peerconnectionModel.status === 'disconnected' - ) { - const closePeerconnectionMessage: ClosePeerconnectionMessage = { - messageType: 'command', - command: 'closePeerconnection', - connectionUrl: peerconnectionUrlFromId(peerconnectionModel.uuid), - } + const closePeerconnectionMessage: ClosePeerconnectionMessage = { + messageType: 'command', + command: 'closePeerconnection', + connectionUrl: peerconnectionUrlFromId(peerconnectionModel.uuid), + } + // TODO: handle possible errors + try { await apiClient.sendSignalingMessage( peerconnectionModel.deviceA.url, closePeerconnectionMessage, peerconnectionUrlFromId(peerconnectionModel.uuid) ) + } catch (error) { + console.error(error) + } + try { await apiClient.sendSignalingMessage( peerconnectionModel.deviceB.url, closePeerconnectionMessage, peerconnectionUrlFromId(peerconnectionModel.uuid) ) - - await sendClosedCallback(peerconnectionModel) - await sendStatusChangedCallback(peerconnectionModel) + } catch (error) { + console.error(error) } + await sendClosedCallback(peerconnectionModel) + await sendStatusChangedCallback(peerconnectionModel) + await peerconnectionRepository.remove(peerconnectionModel) console.log(`deletePeerconnectionsByPeerconnectionId succeeded`) diff --git a/services/device/src/operations/peerconnections/peerconnection/device_status/patch.ts b/services/device/src/operations/peerconnections/peerconnection/device_status/patch.ts index f798c6b1..25851d8a 100644 --- a/services/device/src/operations/peerconnections/peerconnection/device_status/patch.ts +++ b/services/device/src/operations/peerconnections/peerconnection/device_status/patch.ts @@ -40,22 +40,23 @@ export const patchPeerconnectionsByPeerconnectionIdDeviceStatus: patchPeerconnec const oldStatus = peerconnectionModel.status if ( - peerconnectionModel.deviceA.status === 'failed' || - peerconnectionModel.deviceB.status === 'failed' - ) { - peerconnectionModel.status = 'failed' - } else if ( + peerconnectionModel.status === 'closed' || peerconnectionModel.deviceA.status === 'closed' || peerconnectionModel.deviceB.status === 'closed' ) { peerconnectionModel.status = 'closed' + } else if ( + peerconnectionModel.deviceA.status === 'failed' || + peerconnectionModel.deviceB.status === 'failed' + ) { + peerconnectionModel.status = 'failed' } else if ( peerconnectionModel.deviceA.status === 'disconnected' || peerconnectionModel.deviceB.status === 'disconnected' ) { peerconnectionModel.status = 'disconnected' } else if ( - peerconnectionModel.deviceA.status === 'connecting' && + peerconnectionModel.deviceA.status === 'connecting' || peerconnectionModel.deviceB.status === 'connecting' ) { peerconnectionModel.status = 'connecting' @@ -64,11 +65,15 @@ export const patchPeerconnectionsByPeerconnectionIdDeviceStatus: patchPeerconnec peerconnectionModel.deviceB.status === 'connected' ) { peerconnectionModel.status = 'connected' + } else { + peerconnectionModel.status = 'new' } if (peerconnectionModel.status !== oldStatus) await sendStatusChangedCallback(peerconnectionModel) + await peerconnectionRepository.save(peerconnectionModel) + console.log(`patchPeerconnectionsByPeerconnectionIdDeviceStatus succeeded`) return { diff --git a/services/device/test/operations/devices/device/availability/post.spec.ts b/services/device/test/operations/devices/device/availability/post.spec.ts index 0787928b..97aa5308 100644 --- a/services/device/test/operations/devices/device/availability/post.spec.ts +++ b/services/device/test/operations/devices/device/availability/post.spec.ts @@ -53,7 +53,5 @@ export default function (context: Mocha.Context, testData: TestData) { } ) - addTest(suite, '') - return suite } diff --git a/services/device/test/operations/devices/device/index.spec.ts b/services/device/test/operations/devices/device/index.spec.ts index f5308f51..f7b02805 100644 --- a/services/device/test/operations/devices/device/index.spec.ts +++ b/services/device/test/operations/devices/device/index.spec.ts @@ -3,5 +3,15 @@ import deleteSpec from './delete.spec' import getSpec from './get.spec' import patchSpec from './patch.spec' import postSpec from './post.spec' +import signalingSpec from './signaling/index.spec' +import websocketSpec from './websocket/index.spec' -export default [...availabilitySpec, deleteSpec, getSpec, patchSpec, postSpec] +export default [ + getSpec, + postSpec, + patchSpec, + deleteSpec, + ...availabilitySpec, + ...signalingSpec, + ...websocketSpec, +] diff --git a/services/device/test/operations/devices/device/signaling/post.spec.ts b/services/device/test/operations/devices/device/signaling/post.spec.ts index e68b9a63..aad308db 100644 --- a/services/device/test/operations/devices/device/signaling/post.spec.ts +++ b/services/device/test/operations/devices/device/signaling/post.spec.ts @@ -1,8 +1,172 @@ +import { SignalingMessage } from '../../../../../src/generated/types' +import { apiClient } from '../../../../../src/globals' +import { deviceUrlFromId } from '../../../../../src/methods/urlFromId' +import { + connectedDevices, + postDevicesByDeviceIdSignaling, +} from '../../../../../src/operations/devices' import { TestData } from '../../../../data/index.spec' +import { addTest } from '../../../index.spec' +import { + ForbiddenOperationError, + MissingEntityError, + UnrelatedPeerconnectionError, +} from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' +import * as sinon from 'sinon' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('POST /devices/{device_id}/signaling', context) + const PEERCONNECTION_URL = + testData.peerconnections['example peerconnection'].response.url + const INSTANTIABLE_DEVICE_ID = + testData['instantiable browser devices']['instantiable browser device'].model.uuid + const CONCRETE_DEVICE_ID = testData['concrete devices']['concrete device'].model.uuid + + const SIGNALING_MESSAGE: SignalingMessage = { + messageType: 'signaling', + connectionUrl: PEERCONNECTION_URL, + signalingType: 'offer', + content: {}, + } + + const getPeerconnectionStub = sinon.stub(apiClient, 'getPeerconnection') + + suite.afterEach(function () { + getPeerconnectionStub.reset() + getPeerconnectionStub.resolves({ + url: 'https://localhost/peerconnections/bf909997-71a7-4d42-8352-99cb3c276f59', + type: 'webrtc', + devices: [ + { url: deviceUrlFromId(CONCRETE_DEVICE_ID) }, + { url: 'https://localhost/devices/deviceB' }, + ], + }) + }) + + suite.afterAll(function () { + getPeerconnectionStub.restore() + connectedDevices.clear() + }) + + addTest( + suite, + 'should throw a MissingEntityError if the requested device cannot be found', + async function () { + await assert.rejects( + async () => { + await postDevicesByDeviceIdSignaling( + { + device_id: 'non-existent', + peerconnection_url: PEERCONNECTION_URL, + }, + SIGNALING_MESSAGE, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert.strictEqual(error.status, 404) + return true + } + ) + } + ) + + addTest( + suite, + "should throw a ForbiddenOperationError if type of requested device is not 'device'", + async function () { + await assert.rejects( + async () => { + await postDevicesByDeviceIdSignaling( + { + device_id: INSTANTIABLE_DEVICE_ID, + peerconnection_url: PEERCONNECTION_URL, + }, + SIGNALING_MESSAGE, + testData.userData + ) + }, + (error) => { + assert(error instanceof ForbiddenOperationError) + assert.strictEqual(error.status, 400) + return true + } + ) + } + ) + + addTest( + suite, + 'should throw an UnrelatedPeerconnectionError if the device is not taking part in the peerconnection', + async function () { + getPeerconnectionStub.resolves({ + url: 'https://localhost/peerconnections/bf909997-71a7-4d42-8352-99cb3c276f59', + type: 'webrtc', + devices: [ + { url: 'https://localhost/devices/deviceA' }, + { url: 'https://localhost/devices/deviceB' }, + ], + }) + await assert.rejects( + async () => { + await postDevicesByDeviceIdSignaling( + { + device_id: CONCRETE_DEVICE_ID, + peerconnection_url: PEERCONNECTION_URL, + }, + SIGNALING_MESSAGE, + testData.userData + ) + }, + (error) => { + assert(error instanceof UnrelatedPeerconnectionError) + assert.strictEqual(error.status, 400) + return true + } + ) + } + ) + + addTest( + suite, + 'should throw a MissingEntityError if the device does not have a websocket connection', + async function () { + await assert.rejects( + async () => { + await postDevicesByDeviceIdSignaling( + { + device_id: CONCRETE_DEVICE_ID, + peerconnection_url: PEERCONNECTION_URL, + }, + SIGNALING_MESSAGE, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert.strictEqual(error.status, 404) + return true + } + ) + } + ) + + addTest(suite, 'should successfully send the signaling message', async function () { + connectedDevices.set(CONCRETE_DEVICE_ID, { send: () => undefined } as any) + const result = await postDevicesByDeviceIdSignaling( + { + device_id: CONCRETE_DEVICE_ID, + peerconnection_url: PEERCONNECTION_URL, + }, + SIGNALING_MESSAGE, + testData.userData + ) + assert.strictEqual(result.status, 200) + }) + return suite } diff --git a/services/device/test/operations/devices/device/websocket/post.spec.ts b/services/device/test/operations/devices/device/websocket/post.spec.ts index 675407ca..c8c10809 100644 --- a/services/device/test/operations/devices/device/websocket/post.spec.ts +++ b/services/device/test/operations/devices/device/websocket/post.spec.ts @@ -1,8 +1,106 @@ +import { deviceRepository } from '../../../../../src/database/repositories/device' +import { postDevicesByDeviceIdWebsocket } from '../../../../../src/operations/devices' import { TestData } from '../../../../data/index.spec' +import { addTest } from '../../../index.spec' +import { ForbiddenOperationError, MissingEntityError } from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' +import * as sinon from 'sinon' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('POST /devices/{device_id}/websocket', context) + const INSTANTIABLE_DEVICE_ID = + testData['instantiable browser devices']['instantiable browser device'].model.uuid + const CONCRETE_DEVICE_ID = testData['concrete devices']['concrete device'].model.uuid + + let deviceRepositorySaveStub: sinon.SinonSpy< + Parameters, + ReturnType + > + + let clock: sinon.SinonFakeTimers + + suite.beforeAll(function () { + clock = sinon.useFakeTimers() + deviceRepositorySaveStub = sinon.spy(deviceRepository, 'save') + }) + + suite.beforeEach(function () { + deviceRepositorySaveStub.resetHistory() + }) + + suite.afterAll(function () { + deviceRepositorySaveStub.restore() + clock.restore() + }) + + addTest( + suite, + 'should throw a MissingEntityError if the requested device cannot be found', + async function () { + await assert.rejects( + async () => { + await postDevicesByDeviceIdWebsocket( + { device_id: 'non-existent' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert.strictEqual(error.status, 404) + return true + } + ) + } + ) + + addTest( + suite, + "should throw a ForbiddenOperationError if the device is not of type 'device'", + async function () { + await assert.rejects( + async () => { + await postDevicesByDeviceIdWebsocket( + { + device_id: INSTANTIABLE_DEVICE_ID, + }, + testData.userData + ) + }, + (error) => { + assert(error instanceof ForbiddenOperationError) + assert.strictEqual(error.status, 400) + return true + } + ) + } + ) + + addTest( + suite, + 'should successfully generate the websocket token and remove it after 5 minutes', + async function () { + const result = await postDevicesByDeviceIdWebsocket( + { device_id: CONCRETE_DEVICE_ID }, + testData.userData + ) + + assert.strictEqual(result.status, 200) + assert(typeof result.body === 'string') + assert(result.body.length > 0) + assert(deviceRepositorySaveStub.calledOnce) + const argumentFirstCall = deviceRepositorySaveStub.args[0][0] + assert.strictEqual(argumentFirstCall.type, 'device') + assert.strictEqual(argumentFirstCall.token, result.body) + + await clock.tickAsync(5 * 60 * 1000) + assert(deviceRepositorySaveStub.calledTwice) + const argumentSecondCall = deviceRepositorySaveStub.args[0][0] + assert.strictEqual(argumentSecondCall.type, 'device') + assert.strictEqual(argumentSecondCall.token, undefined) + } + ) + return suite } diff --git a/services/device/test/operations/peerconnections/index.spec.ts b/services/device/test/operations/peerconnections/index.spec.ts index 1ac2862c..dfca3f39 100644 --- a/services/device/test/operations/peerconnections/index.spec.ts +++ b/services/device/test/operations/peerconnections/index.spec.ts @@ -1,4 +1,5 @@ import getSpec from './get.spec' +import peerconnectionSpec from './peerconnection/index.spec' import postSpec from './post.spec' -export default [getSpec, postSpec] +export default [getSpec, postSpec, ...peerconnectionSpec] diff --git a/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts b/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts index efafe2a1..2e0e23ac 100644 --- a/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts +++ b/services/device/test/operations/peerconnections/peerconnection/delete.spec.ts @@ -1,8 +1,100 @@ +import { peerconnectionRepository } from '../../../../src/database/repositories/peerconnection' +import { apiClient } from '../../../../src/globals' +import * as callbackFunctions from '../../../../src/methods/callbacks' +import { deletePeerconnectionsByPeerconnectionId } from '../../../../src/operations/peerconnections' import { TestData } from '../../../data/index.spec' +import { peerconnectionNames } from '../../../data/peerconnections/index.spec' +import { addTest } from '../../index.spec' +import { MissingEntityError } from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' +import * as sinon from 'sinon' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('DELETE /peerconnections/{peerconnection_id}', context) + const peerconnectionRepositoryFindOneOrFailOriginal = + peerconnectionRepository.findOneOrFail + let peerconnectionRepositoryFindOneOrFailStub: sinon.SinonStub< + Parameters, + ReturnType + > + let sendSignalingMessageStub: sinon.SinonStub< + Parameters, + ReturnType + > + let sendClosedCallbackStub: sinon.SinonStub< + Parameters, + ReturnType + > + let sendStatusChangedCallbackStub: sinon.SinonStub< + Parameters, + ReturnType + > + + suite.beforeAll(function () { + peerconnectionRepositoryFindOneOrFailStub = sinon.stub( + peerconnectionRepository, + 'findOneOrFail' + ) + sendSignalingMessageStub = sinon.stub(apiClient, 'sendSignalingMessage') + sendClosedCallbackStub = sinon.stub(callbackFunctions, 'sendClosedCallback') + sendStatusChangedCallbackStub = sinon.stub( + callbackFunctions, + 'sendStatusChangedCallback' + ) + }) + + suite.beforeEach(function () { + peerconnectionRepositoryFindOneOrFailStub.callsFake( + peerconnectionRepositoryFindOneOrFailOriginal + ) + }) + + suite.afterAll(function () { + peerconnectionRepositoryFindOneOrFailStub.restore() + sendSignalingMessageStub.restore() + sendClosedCallbackStub.restore() + sendStatusChangedCallbackStub.restore() + }) + + addTest(suite, 'should delete the peerconnection', async function () { + for (const peerconnectionName of peerconnectionNames) { + const peerconnectionModel = testData.peerconnections[peerconnectionName].model + const result = await deletePeerconnectionsByPeerconnectionId( + { peerconnection_id: peerconnectionModel.uuid }, + testData.userData + ) + assert.strictEqual(result.status, 204) + assert( + (await peerconnectionRepository.findOne({ + where: { + uuid: peerconnectionModel.uuid, + }, + })) === null + ) + } + }) + + addTest( + suite, + 'should throw a MissingEntityError if peerconnection is not found', + async function () { + await assert.rejects( + async () => { + await deletePeerconnectionsByPeerconnectionId( + { peerconnection_id: 'non-existent' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert.strictEqual(error.status, 404) + return true + } + ) + } + ) + return suite } diff --git a/services/device/test/operations/peerconnections/peerconnection/device_status/patch.spec.ts b/services/device/test/operations/peerconnections/peerconnection/device_status/patch.spec.ts index 13e45076..9c9f1eb3 100644 --- a/services/device/test/operations/peerconnections/peerconnection/device_status/patch.spec.ts +++ b/services/device/test/operations/peerconnections/peerconnection/device_status/patch.spec.ts @@ -1,5 +1,17 @@ +import { PeerconnectionModel } from '../../../../../src/database/model' +import { peerconnectionRepository } from '../../../../../src/database/repositories/peerconnection' +import { ConnectionStatus } from '../../../../../src/generated/types' +import * as callbackFunctions from '../../../../../src/methods/callbacks' +import { patchPeerconnectionsByPeerconnectionIdDeviceStatus } from '../../../../../src/operations/peerconnections' import { TestData } from '../../../../data/index.spec' +import { addTest } from '../../../index.spec' +import { + MissingEntityError, + UnrelatedPeerconnectionError, +} from '@crosslab/service-common' +import assert, { AssertionError } from 'assert' import Mocha from 'mocha' +import * as sinon from 'sinon' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite( @@ -7,5 +19,232 @@ export default function (context: Mocha.Context, testData: TestData) { context ) + const PEERCONNECTION = testData.peerconnections['example peerconnection'] + const PEERCONNECTION_ID = PEERCONNECTION.model.uuid + const DEVICE_A_URL = PEERCONNECTION.model.deviceA.url + const DEVICE_B_URL = PEERCONNECTION.model.deviceB.url + + let sendStatusChangedCallbackStub: sinon.SinonStub< + Parameters, + ReturnType + > + let peerconnectionRepositoryFindOneOrFailStub: sinon.SinonStub< + Parameters, + ReturnType + > + const peerconnectionRepositoryFindOneOrFailOriginal = + peerconnectionRepository.findOneOrFail + + suite.beforeAll(function () { + sendStatusChangedCallbackStub = sinon.stub( + callbackFunctions, + 'sendStatusChangedCallback' + ) + peerconnectionRepositoryFindOneOrFailStub = sinon.stub( + peerconnectionRepository, + 'findOneOrFail' + ) + }) + + suite.beforeEach(function () { + sendStatusChangedCallbackStub.resetHistory() + peerconnectionRepositoryFindOneOrFailStub.callsFake( + peerconnectionRepositoryFindOneOrFailOriginal + ) + }) + + suite.afterAll(function () { + sendStatusChangedCallbackStub.restore() + peerconnectionRepositoryFindOneOrFailStub.restore() + }) + + addTest( + suite, + 'should throw a MissingEntityError if the requested peerconnection cannot be found', + async function () { + await assert.rejects( + async () => { + await patchPeerconnectionsByPeerconnectionIdDeviceStatus( + { + peerconnection_id: 'non-existent', + device_url: DEVICE_A_URL, + }, + { status: 'closed' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert.strictEqual(error.status, 404) + return true + } + ) + } + ) + + addTest( + suite, + 'should throw an UnrelatedPeerconnectionError if the device is not part of the peerconnection', + async function () { + await assert.rejects( + async () => { + await patchPeerconnectionsByPeerconnectionIdDeviceStatus( + { + peerconnection_id: PEERCONNECTION_ID, + device_url: 'https://localhost/devices/unrelated', + }, + { status: 'new' }, + testData.userData + ) + }, + (error) => { + assert(error instanceof UnrelatedPeerconnectionError) + assert.strictEqual(error.status, 400) + return true + } + ) + } + ) + + const possibleStates: ConnectionStatus[] = [ + 'closed', + 'connected', + 'connecting', + 'disconnected', + 'failed', + 'new', + ] + const testCases: { + deviceUrl: string + newStatus: ConnectionStatus + statusDeviceA: ConnectionStatus + statusDeviceB: ConnectionStatus + statusPeerconnection: ConnectionStatus + expectedStatusPeerconnection: ConnectionStatus + shouldSendCallback: boolean + }[] = [] + + function getExpectedStatusPeerconnection( + statusPeerconnection: ConnectionStatus, + statusDeviceA: ConnectionStatus, + statusDeviceB: ConnectionStatus + ): ConnectionStatus { + return statusPeerconnection === 'closed' || + statusDeviceA === 'closed' || + statusDeviceB === 'closed' + ? 'closed' + : statusDeviceA === 'failed' || statusDeviceB === 'failed' + ? 'failed' + : statusDeviceA === 'disconnected' || statusDeviceB === 'disconnected' + ? 'disconnected' + : statusDeviceA === 'connecting' || statusDeviceB === 'connecting' + ? 'connecting' + : statusDeviceA === 'connected' && statusDeviceB === 'connected' + ? 'connected' + : 'new' + } + + for (const deviceUrl of [DEVICE_A_URL, DEVICE_B_URL]) { + for (const newStatus of possibleStates) { + for (const statusDeviceA of possibleStates) { + for (const statusDeviceB of possibleStates) { + for (const statusPeerconnection of possibleStates) { + const expectedStatusPeerconnection = + deviceUrl === DEVICE_A_URL + ? getExpectedStatusPeerconnection( + statusPeerconnection, + newStatus, + statusDeviceB + ) + : getExpectedStatusPeerconnection( + statusPeerconnection, + statusDeviceA, + newStatus + ) + + testCases.push({ + deviceUrl, + newStatus, + statusDeviceA, + statusDeviceB, + statusPeerconnection, + expectedStatusPeerconnection, + shouldSendCallback: + statusPeerconnection !== expectedStatusPeerconnection, + }) + } + } + } + } + } + + addTest( + suite, + `should successfully change status of device and peerconnection`, + async function (this: Mocha.Context) { + this.timeout(testCases.length * 100) + this.slow(testCases.length * 20) + + for (const testCase of testCases) { + try { + const PEERCONNECTION_MODEL: PeerconnectionModel = { + uuid: PEERCONNECTION_ID, + type: 'webrtc', + status: testCase.statusPeerconnection, + deviceA: { + url: DEVICE_A_URL, + status: testCase.statusDeviceA, + }, + deviceB: { + url: DEVICE_B_URL, + status: testCase.statusDeviceB, + }, + } + peerconnectionRepositoryFindOneOrFailStub.resolves( + PEERCONNECTION_MODEL + ) + + const result = + await patchPeerconnectionsByPeerconnectionIdDeviceStatus( + { + device_url: testCase.deviceUrl, + peerconnection_id: PEERCONNECTION_ID, + }, + { status: testCase.newStatus }, + testData.userData + ) + + assert.strictEqual(result.status, 201) + assert.strictEqual( + PEERCONNECTION_MODEL.status, + testCase.expectedStatusPeerconnection + ) + if (testCase.deviceUrl === DEVICE_A_URL) + assert.strictEqual( + PEERCONNECTION_MODEL.deviceA.status, + testCase.newStatus + ) + else + assert.strictEqual( + PEERCONNECTION_MODEL.deviceB.status, + testCase.newStatus + ) + if (testCase.shouldSendCallback) + assert(sendStatusChangedCallbackStub.calledOnce) + else assert(sendStatusChangedCallbackStub.callCount === 0) + + sendStatusChangedCallbackStub.resetHistory() + } catch (error) { + assert(error instanceof AssertionError) + error.message = JSON.stringify(testCase, null, 4).replaceAll( + '\n', + '\n\t' + ) + throw error + } + } + } + ) + return suite } diff --git a/services/device/test/operations/peerconnections/peerconnection/get.spec.ts b/services/device/test/operations/peerconnections/peerconnection/get.spec.ts index 480ab999..197936cb 100644 --- a/services/device/test/operations/peerconnections/peerconnection/get.spec.ts +++ b/services/device/test/operations/peerconnections/peerconnection/get.spec.ts @@ -1,8 +1,55 @@ +import { getPeerconnectionsByPeerconnectionId } from '../../../../src/operations/peerconnections' import { TestData } from '../../../data/index.spec' +import { peerconnectionNames } from '../../../data/peerconnections/index.spec' +import { peerconnectionRepositoryTestSuite } from '../../../database/repositories/peerconnection.spec' +import { addTest } from '../../index.spec' +import { MissingEntityError } from '@crosslab/service-common' +import assert from 'assert' import Mocha from 'mocha' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('GET /peerconnections/{peerconnection_id}', context) + addTest( + suite, + 'should throw a MissingEntityError if the requested peerconnection cannot be found', + async function () { + await assert.rejects( + async () => { + await getPeerconnectionsByPeerconnectionId( + { + peerconnection_id: 'non-existent', + }, + testData.userData + ) + }, + (error) => { + assert(error instanceof MissingEntityError) + assert.strictEqual(error.status, 404) + return true + } + ) + } + ) + + addTest(suite, 'should return the requested peerconnection', async function () { + for (const peerconnectionName of peerconnectionNames) { + const peerconnection = testData.peerconnections[peerconnectionName] + const result = await getPeerconnectionsByPeerconnectionId( + { + peerconnection_id: peerconnection.model.uuid, + }, + testData.userData + ) + assert.strictEqual(result.status, 200) + assert( + peerconnectionRepositoryTestSuite.validateFormat( + peerconnection.model, + result.body + ) + ) + } + }) + return suite } diff --git a/services/device/test/operations/peerconnections/peerconnection/index.spec.ts b/services/device/test/operations/peerconnections/peerconnection/index.spec.ts index 64c40ef7..2473cc63 100644 --- a/services/device/test/operations/peerconnections/peerconnection/index.spec.ts +++ b/services/device/test/operations/peerconnections/peerconnection/index.spec.ts @@ -1,4 +1,5 @@ import deleteSpec from './delete.spec' +import deviceStatusSpec from './device_status/index.spec' import getSpec from './get.spec' -export default [deleteSpec, getSpec] +export default [deleteSpec, getSpec, ...deviceStatusSpec] From 4353bff6d2f34c6979039506645e459431196f66 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 24 Apr 2023 17:14:02 +0200 Subject: [PATCH 28/33] Fix client generation --- .../package-lock.json | 6 +- .../filters/format/formatExpressPath.ts | 10 +++- .../typescript/filters/format/formatName.ts | 25 +++++++- .../filters/format/formatOperation.ts | 24 +++++++- .../filters/typing/standaloneTypings.ts | 2 +- .../filterCollections/typescript/format.ts | 59 ------------------- .../typescript/resolve/resolveOperations.ts | 7 ++- .../typescript/resolve/resolveSchemas.ts | 3 +- .../typescript/typings/destructure.ts | 2 +- .../typescript/typings/typing.ts | 2 +- .../templates/client/client.ts.njk | 8 +-- .../templates/client/signatures.ts.njk | 8 +-- 12 files changed, 77 insertions(+), 79 deletions(-) delete mode 100644 helper/crosslab-typescript-addon/src/filterCollections/typescript/format.ts diff --git a/helper/crosslab-typescript-addon/package-lock.json b/helper/crosslab-typescript-addon/package-lock.json index 64a38145..6e3ae19b 100644 --- a/helper/crosslab-typescript-addon/package-lock.json +++ b/helper/crosslab-typescript-addon/package-lock.json @@ -40,6 +40,7 @@ "ajv-formats": "^2.1.1", "commander": "^9.4.1", "deterministic-json-schema-faker": "^0.5.0-rcv.46", + "json-schema-merge-allof": "^0.8.1", "json-schema-to-typescript": "^10.1.5", "nunjucks": "^3.2.3", "prettier": "^2.6.2", @@ -2651,8 +2652,9 @@ "dev": true }, "node_modules/nunjucks": { - "version": "3.2.3", - "license": "BSD-2-Clause", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz", + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", "peer": true, "dependencies": { "a-sync-waterfall": "^1.0.0", diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatExpressPath.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatExpressPath.ts index d2065131..700069bf 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatExpressPath.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatExpressPath.ts @@ -1,6 +1,14 @@ -import { formatExpressPath } from '../../format' import { Filter } from '@cross-lab-project/openapi-codegen' +/** + * This function formats the path of an operation to an express path. + * @param path The path of the operation. + * @returns A valid express path. + */ +export function formatExpressPath(path: string) { + return path.replace(/\{(.*?)\}/g, ':$1') +} + export const formatExpressPathFilter: Filter = { name: 'formatExpressPath', function: formatExpressPath, diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatName.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatName.ts index 771c3569..a8d01fe1 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatName.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatName.ts @@ -1,6 +1,29 @@ -import { formatName } from '../../format' import { Filter } from '@cross-lab-project/openapi-codegen' +/** + * formats the name of an object as follows: + * device_id -> DeviceId + * @param name name to be formatted + * @param capitalize determines whether the first letter should be capitalized + * @returns formatted name + */ +export function formatName(name: string, capitalize = true) { + const split = name.split(/[ _-]/) + const result = split + .map((el) => { + if (el.length > 1) { + return el.charAt(0).toUpperCase() + el.slice(1) + } else { + return el.toUpperCase() + } + }) + .join('') + + if (!capitalize) return result.charAt(0).toLowerCase() + result.slice(1) + + return result +} + export const formatNameFilter: Filter = { name: 'formatName', function: formatName, diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatOperation.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatOperation.ts index 08294ad1..4472122e 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatOperation.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/format/formatOperation.ts @@ -1,6 +1,28 @@ -import { formatOperation } from '../../format' import { Filter } from '@cross-lab-project/openapi-codegen' +/** + * This function formats the path of an operation. + * @param path The path of the operation. + * @param method The method of the operation. + * @param capitalize If true, the first letter will be capitalized. + * @returns The formatted operation path. + */ +export function formatOperation(path: string, method: string, capitalize = false) { + const splitPath = path.replace(/\{/g, '_by_').replace(/\}/g, '').split('/') + const formattedPath = splitPath + .map((s) => + s + .split('_') + .map((is) => is.charAt(0).toUpperCase() + is.slice(1)) + .join('') + ) + .join('') + const formattedMethod = capitalize + ? method.charAt(0).toUpperCase() + method.slice(1).toLowerCase() + : method.toLowerCase() + return formattedMethod + formattedPath +} + export const formatOperationFilter: Filter = { name: 'formatOperation', function: formatOperation, diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/standaloneTypings.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/standaloneTypings.ts index 04ef9f47..c13ec924 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/standaloneTypings.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/typing/standaloneTypings.ts @@ -1,6 +1,6 @@ -import { formatName } from '../../format' import { ExtendedSchema } from '../../types' import { generateTyping } from '../../typings/typing' +import { formatName } from '../format/formatName' import { Filter } from '@cross-lab-project/openapi-codegen' /** diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/format.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/format.ts deleted file mode 100644 index 97458d2b..00000000 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/format.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * This function formats the path of an operation. - * @param path The path of the operation. - * @param method The method of the operation. - * @param capitalize If true, the first letter will be capitalized. - * @returns The formatted operation path. - */ -export function formatOperation( - path: string, - method: string, - capitalize = false -) { - const splitPath = path.replace(/\{/g, '_by_').replace(/\}/g, '').split('/') - const formattedPath = splitPath - .map((s) => - s - .split('_') - .map((is) => is.charAt(0).toUpperCase() + is.slice(1)) - .join('') - ) - .join('') - const formattedMethod = capitalize - ? method.charAt(0).toUpperCase() + method.slice(1).toLowerCase() - : method.toLowerCase() - return formattedMethod + formattedPath -} - -/** - * formats the name of an object as follows: - * device_id -> DeviceId - * @param name name to be formatted - * @param capitalize determines whether the first letter should be capitalized - * @returns formatted name - */ -export function formatName(name: string, capitalize = true) { - const split = name.split(/[ _-]/) - const result = split - .map((el) => { - if (el.length > 1) { - return el.charAt(0).toUpperCase() + el.slice(1) - } else { - return el.toUpperCase() - } - }) - .join('') - - if (!capitalize) return result.charAt(0).toLowerCase() + result.slice(1) - - return result -} - -/** - * This function formats the path of an operation to an express path. - * @param path The path of the operation. - * @returns A valid express path. - */ -export function formatExpressPath(path: string) { - return path.replace(/\{(.*?)\}/g, ':$1') -} diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveOperations.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveOperations.ts index ae7b880f..71d4b727 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveOperations.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveOperations.ts @@ -1,4 +1,5 @@ -import { formatName, formatOperation } from '../format' +import { formatName } from '../filters/format/formatName' +import { formatOperation } from '../filters/format/formatOperation' import { SimplifiedOperation, SimplifiedParameter, SimplifiedResponse } from '../types' import { OpenAPIV3_1 } from 'openapi-types' @@ -37,13 +38,13 @@ function parsePathItem( method as OpenAPIV3_1.HttpMethods ] as OpenAPIV3_1.OperationObject - simplifiedOperations.push(parseMethod(path, method, operation)) + simplifiedOperations.push(parseOperation(path, method, operation)) } return simplifiedOperations } -function parseMethod( +function parseOperation( path: string, method: string, operation: OpenAPIV3_1.OperationObject diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts index f6457f01..88f0349f 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts @@ -1,4 +1,5 @@ -import { formatName, formatOperation } from '../format' +import { formatName } from '../filters/format/formatName' +import { formatOperation } from '../filters/format/formatOperation' import { userTypeSchema } from '../schemas/userType' import { ExtendedSchema } from '../types' import { removeReadOnly, removeWriteOnly } from './removeReadWriteOnly' diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts index 65ee7618..4950ba8e 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts @@ -1,4 +1,4 @@ -import { formatName } from '../format' +import { formatName } from '../filters/format/formatName' import { DestructuredSchema, ExtendedSchema } from '../types' import { generateTyping } from './typing' import { OpenAPIV3_1 } from 'openapi-types' diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts index 9993a923..acfcee40 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts @@ -1,4 +1,4 @@ -import { formatName } from '../format' +import { formatName } from '../filters/format/formatName' import { ExtendedSchema } from '../types' import { handleAllOf } from './keywords/allOf' import { handleAnyOf } from './keywords/anyOf' diff --git a/helper/crosslab-typescript-addon/templates/client/client.ts.njk b/helper/crosslab-typescript-addon/templates/client/client.ts.njk index 1cec03bf..bc19d60c 100644 --- a/helper/crosslab-typescript-addon/templates/client/client.ts.njk +++ b/helper/crosslab-typescript-addon/templates/client/client.ts.njk @@ -260,7 +260,7 @@ export class APIClient { {#- Destructure request body schema #} {%- set destructured = ( operation.requestBody.schema | destructureSchema({ - "prefixTypes": (operation.serviceName | formatName) + "Types." + "prefixDirectlyResolved": (operation.serviceName | formatName) + "Types." }) ) if operation.requestBody else [] %} @@ -278,7 +278,7 @@ export class APIClient { {%- if operation.parameters %} {%- for parameter in operation.parameters | select("attrequalto", ["required", true]) %} {%- if parameter.in != "path" or buildUrl %} - {{ parameter.name }}: {{ parameter.schema | typeDeclaration({ "prefixTypes": (operation.serviceName | formatName) + "Types.", "inline": true }) }} + {{ parameter.name }}: {{ parameter.schema | typeDeclaration({ "prefixDirectlyResolved": (operation.serviceName | formatName) + "Types.", "inline": true }) }} {%- endif %} {%- endfor %} {%- endif %} @@ -295,7 +295,7 @@ export class APIClient { {#- Add optional parameters #} {%- if operation.parameters %} {%- for parameter in operation.parameters | select("attrequalto", ["required", false]) %} - {{ parameter.name }}?: {{ parameter.schema | typeDeclaration({ "prefixTypes": (operation.serviceName | formatName) + "Types.", "inline": true }) }} + {{ parameter.name }}?: {{ parameter.schema | typeDeclaration({ "prefixDirectlyResolved": (operation.serviceName | formatName) + "Types.", "inline": true }) }} {%- endfor %} {%- endif %} {{- "url?: string" if optionalUrl -}} @@ -372,7 +372,7 @@ export class APIClient { {#- Add declaration of request body if defined #} {%- if operation.requestBody -%} {{- bodyName + ": " -}} - {{- operation.requestBody.schema | typeDeclaration(schemas, { "prefixTypes": types + ".", "schemaType": "request" }) if operation.requestBody.schema else signatures + "." + cap_name + "Body" -}}, + {{- operation.requestBody.schema | typeDeclaration(schemas, { "prefixDirectlyResolved": types + ".", "schemaType": "request" }) if operation.requestBody.schema else signatures + "." + cap_name + "Body" -}}, {%- endif -%} {#- Add declaration of parameters and optional url if defined #} diff --git a/helper/crosslab-typescript-addon/templates/client/signatures.ts.njk b/helper/crosslab-typescript-addon/templates/client/signatures.ts.njk index cf79e419..009ec6d4 100644 --- a/helper/crosslab-typescript-addon/templates/client/signatures.ts.njk +++ b/helper/crosslab-typescript-addon/templates/client/signatures.ts.njk @@ -82,7 +82,7 @@ export namespace {{ serviceName | formatName }}Signatures { {% for parameter in operation.parameters -%} {%- set temp = '"' + parameter.name + '"' -%} {%- set temp = temp + ("?" if not parameter.required) + ": " -%} - {%- set temp = temp + (parameter.schema | typeDeclaration(sortedSchemas[serviceName], { "prefixTypes": types + ".", "schemaType": "request" }) | indent(4)) -%} + {%- set temp = temp + (parameter.schema | typeDeclaration(sortedSchemas[serviceName], { "prefixDirectlyResolved": types + ".", "schemaType": "request" }) | indent(4)) -%} {%- set parametersTypeDeclarations = (parametersTypeDeclarations.push(temp), parametersTypeDeclarations) -%} {%- endfor -%} {{ parametersTypeDeclarations | join(",\n\t") }}, @@ -102,7 +102,7 @@ export namespace {{ serviceName | formatName }}Signatures { * @category {{ low_name }}() */ export type {{ cap_name }}Body = - {{- " " + operation.requestBody.schema | typeDeclaration(sortedSchemas[serviceName], { "prefixTypes": types + ".", "schemaType": "request" }) | indent(4) if operation.requestBody.schema}} + {{- " " + operation.requestBody.schema | typeDeclaration(sortedSchemas[serviceName], { "prefixDirectlyResolved": types + ".", "schemaType": "request" }) | indent(4) if operation.requestBody.schema}} {{- " | undefined" if not operation.requestBody.required }} {%- endif %} @@ -146,7 +146,7 @@ export namespace {{ serviceName | formatName }}Signatures { {%- set responseBody = "undefined" -%} {%- if response.schema -%} - {%- set responseBody = response.schema | typeDeclaration(sortedSchemas[serviceName], { "prefixTypes": types + ".", "schemaType": "response" }) | indent(8) -%} + {%- set responseBody = response.schema | typeDeclaration(sortedSchemas[serviceName], { "prefixDirectlyResolved": types + ".", "schemaType": "response" }) | indent(8) -%} {%- endif %} /** @@ -157,7 +157,7 @@ export namespace {{ serviceName | formatName }}Signatures { status: {{ response.status }} headers{{ "?" if not response.headers }}: { {% for header in response.headers -%} - "{{ header.name }}"{{ "?" if not header.required}}: {{ header.schema | typeDeclaration(sortedSchemas[serviceName], { "prefixTypes": types + ".", "schemaType": "response" }) | indent(12) if header.schema else "undefined" }}, + "{{ header.name }}"{{ "?" if not header.required}}: {{ header.schema | typeDeclaration(sortedSchemas[serviceName], { "prefixDirectlyResolved": types + ".", "schemaType": "response" }) | indent(12) if header.schema else "undefined" }}, {% endfor -%} [k: string]: string | undefined } From a67c71f471007e40c8b5eb5f5145c479e281da8f Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Mon, 24 Apr 2023 17:24:26 +0200 Subject: [PATCH 29/33] Add ImpossibleOperationError and StatusChangedMessage-Schema --- services/common/src/errors.ts | 12 +++++++++++- .../schemas/messages/status_changed_message.yml | 14 ++++++++++++++ .../operations/devices/device/availability/post.ts | 4 ++-- .../device/src/operations/devices/device/post.ts | 6 +++--- .../operations/devices/device/signaling/post.ts | 4 ++-- .../operations/devices/device/websocket/post.ts | 4 ++-- .../devices/device/availability/post.spec.ts | 6 +++--- .../test/operations/devices/device/post.spec.ts | 6 +++--- .../devices/device/signaling/post.spec.ts | 6 +++--- .../devices/device/websocket/post.spec.ts | 6 +++--- 10 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 services/device/api/schemas/messages/status_changed_message.yml diff --git a/services/common/src/errors.ts b/services/common/src/errors.ts index 805e1093..b3e65157 100644 --- a/services/common/src/errors.ts +++ b/services/common/src/errors.ts @@ -39,7 +39,7 @@ export class UnrelatedPeerconnectionError extends ErrorWithStatus { } /** - * This error class should be used if an object is missing a needed property. + * This error class should be used if an operation is forbidden for the user. */ export class ForbiddenOperationError extends ErrorWithStatus { constructor(message: string, status?: number) { @@ -48,6 +48,16 @@ export class ForbiddenOperationError extends ErrorWithStatus { } } +/** + * This error class should be used if an operation is impossible. + */ +export class ImpossibleOperationError extends ErrorWithStatus { + constructor(message: string, status?: number) { + super(message, status); + this.name = 'ImpossibleOperationError'; + } + } + /** * This error class should be used if an object contains an invalid value. */ diff --git a/services/device/api/schemas/messages/status_changed_message.yml b/services/device/api/schemas/messages/status_changed_message.yml new file mode 100644 index 00000000..5f2497e1 --- /dev/null +++ b/services/device/api/schemas/messages/status_changed_message.yml @@ -0,0 +1,14 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +title: Status Changed Message +allOf: + - $ref: "./message.yml" + - type: object + properties: + messageType: + const: status-changed + status: + - $ref: "../peerconnections/peerconnection_status.yml" + required: + - messageType + - status +x-typeguard: true \ No newline at end of file diff --git a/services/device/src/operations/devices/device/availability/post.ts b/services/device/src/operations/devices/device/availability/post.ts index 4d2d75e1..4febfe20 100644 --- a/services/device/src/operations/devices/device/availability/post.ts +++ b/services/device/src/operations/devices/device/availability/post.ts @@ -2,7 +2,7 @@ import { deviceRepository } from '../../../../database/repositories/device' import { postDevicesByDeviceIdAvailabilitySignature } from '../../../../generated/signatures' import { calculateAvailability } from '../../../../methods/availability' import { sendChangedCallback } from '../../../../methods/callbacks' -import { ForbiddenOperationError } from '@crosslab/service-common' +import { ImpossibleOperationError } from '@crosslab/service-common' const YEAR = 365 * 24 * 60 * 60 * 1000 @@ -22,7 +22,7 @@ export const postDevicesByDeviceIdAvailability: postDevicesByDeviceIdAvailabilit }) if (deviceModel.type !== 'device') { - throw new ForbiddenOperationError( + throw new ImpossibleOperationError( `Can only update the availability for a device of type 'device', not for type '${deviceModel.type}'`, 400 ) diff --git a/services/device/src/operations/devices/device/post.ts b/services/device/src/operations/devices/device/post.ts index 49e17aa5..652fbaed 100644 --- a/services/device/src/operations/devices/device/post.ts +++ b/services/device/src/operations/devices/device/post.ts @@ -4,14 +4,14 @@ import { postDevicesByDeviceIdSignature } from '../../../generated/signatures' import { apiClient } from '../../../globals' import { changedCallbacks } from '../../../methods/callbacks' import { deviceUrlFromId } from '../../../methods/urlFromId' -import { ForbiddenOperationError } from '@crosslab/service-common' +import { ImpossibleOperationError } from '@crosslab/service-common' /** * This function implements the functionality for handling POST requests on /devices/{device_id} endpoint. * @param parameters The parameters of the request. * @param user The user submitting the request. * @throws {MissingEntityError} Thrown if device is not found in the database. - * @throws {ForbiddenOperationError} Thrown if device is not instantiable. + * @throws {ImpossibleOperationError} Thrown if device is not instantiable. */ export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( parameters, @@ -27,7 +27,7 @@ export const postDevicesByDeviceId: postDevicesByDeviceIdSignature = async ( instantiableDeviceModel.type !== 'cloud instantiable' && instantiableDeviceModel.type !== 'edge instantiable' ) - throw new ForbiddenOperationError( + throw new ImpossibleOperationError( `Cannot create new instance of device '${deviceUrlFromId( instantiableDeviceModel.uuid )}' since it has type '${instantiableDeviceModel.type}'`, diff --git a/services/device/src/operations/devices/device/signaling/post.ts b/services/device/src/operations/devices/device/signaling/post.ts index 3a360820..c497c66d 100644 --- a/services/device/src/operations/devices/device/signaling/post.ts +++ b/services/device/src/operations/devices/device/signaling/post.ts @@ -4,7 +4,7 @@ import { postDevicesByDeviceIdSignalingSignature } from '../../../../generated/s import { apiClient } from '../../../../globals' import { deviceUrlFromId } from '../../../../methods/urlFromId' import { - ForbiddenOperationError, + ImpossibleOperationError, UnrelatedPeerconnectionError, MissingEntityError, } from '@crosslab/service-common' @@ -28,7 +28,7 @@ export const postDevicesByDeviceIdSignaling: postDevicesByDeviceIdSignalingSigna // Make sure device is a concrete device if (deviceModel.type !== 'device') - throw new ForbiddenOperationError( + throw new ImpossibleOperationError( `Cannot send signaling message to device with type '${deviceModel.type}'`, 400 ) diff --git a/services/device/src/operations/devices/device/websocket/post.ts b/services/device/src/operations/devices/device/websocket/post.ts index 665c5e61..7dd6c550 100644 --- a/services/device/src/operations/devices/device/websocket/post.ts +++ b/services/device/src/operations/devices/device/websocket/post.ts @@ -1,7 +1,7 @@ import { deviceRepository } from '../../../../database/repositories/device' import { postDevicesByDeviceIdWebsocketSignature } from '../../../../generated/signatures' import { - ForbiddenOperationError, + ImpossibleOperationError, MissingEntityError as _MissingEntityError, } from '@crosslab/service-common' import { randomUUID } from 'crypto' @@ -23,7 +23,7 @@ export const postDevicesByDeviceIdWebsocket: postDevicesByDeviceIdWebsocketSigna }) if (deviceModel.type !== 'device') - throw new ForbiddenOperationError( + throw new ImpossibleOperationError( "A websocket token may only be requested for a device of type 'device'", 400 ) diff --git a/services/device/test/operations/devices/device/availability/post.spec.ts b/services/device/test/operations/devices/device/availability/post.spec.ts index 97aa5308..cddb5c5a 100644 --- a/services/device/test/operations/devices/device/availability/post.spec.ts +++ b/services/device/test/operations/devices/device/availability/post.spec.ts @@ -1,7 +1,7 @@ import { postDevicesByDeviceIdAvailability } from '../../../../../src/operations/devices' import { TestData } from '../../../../data/index.spec' import { addTest } from '../../../index.spec' -import { ForbiddenOperationError, MissingEntityError } from '@crosslab/service-common' +import { ImpossibleOperationError, MissingEntityError } from '@crosslab/service-common' import assert from 'assert' import Mocha from 'mocha' @@ -31,7 +31,7 @@ export default function (context: Mocha.Context, testData: TestData) { addTest( suite, - "should throw a ForbiddenOperationError if the device is not of type 'device'", + "should throw a ImpossibleOperationError if the device is not of type 'device'", async function () { await assert.rejects( async () => { @@ -45,7 +45,7 @@ export default function (context: Mocha.Context, testData: TestData) { ) }, (error) => { - assert(error instanceof ForbiddenOperationError) + assert(error instanceof ImpossibleOperationError) assert(error.status === 400) return true } diff --git a/services/device/test/operations/devices/device/post.spec.ts b/services/device/test/operations/devices/device/post.spec.ts index 840c1c6b..05854e8b 100644 --- a/services/device/test/operations/devices/device/post.spec.ts +++ b/services/device/test/operations/devices/device/post.spec.ts @@ -8,7 +8,7 @@ import { instantiableCloudDeviceNames } from '../../../data/devices/instantiable import { TestData } from '../../../data/index.spec' import { concreteDeviceRepositoryTestSuite } from '../../../database/repositories/device/concreteDevice.spec' import { addTest } from '../../index.spec' -import { ForbiddenOperationError, MissingEntityError } from '@crosslab/service-common' +import { ImpossibleOperationError, MissingEntityError } from '@crosslab/service-common' import assert from 'assert' import Mocha from 'mocha' import * as sinon from 'sinon' @@ -79,7 +79,7 @@ export default function (context: Mocha.Context, testData: TestData) { addTest( suite, - 'should throw a ForbiddenOperationError if the device is not instantiable', + 'should throw a ImpossibleOperationError if the device is not instantiable', async function () { const deviceModels = [ testData['concrete devices']['concrete device'].model, @@ -97,7 +97,7 @@ export default function (context: Mocha.Context, testData: TestData) { ) }, (error) => { - assert(error instanceof ForbiddenOperationError) + assert(error instanceof ImpossibleOperationError) assert(error.status === 400) return true } diff --git a/services/device/test/operations/devices/device/signaling/post.spec.ts b/services/device/test/operations/devices/device/signaling/post.spec.ts index aad308db..4f09836d 100644 --- a/services/device/test/operations/devices/device/signaling/post.spec.ts +++ b/services/device/test/operations/devices/device/signaling/post.spec.ts @@ -8,7 +8,7 @@ import { import { TestData } from '../../../../data/index.spec' import { addTest } from '../../../index.spec' import { - ForbiddenOperationError, + ImpossibleOperationError, MissingEntityError, UnrelatedPeerconnectionError, } from '@crosslab/service-common' @@ -77,7 +77,7 @@ export default function (context: Mocha.Context, testData: TestData) { addTest( suite, - "should throw a ForbiddenOperationError if type of requested device is not 'device'", + "should throw a ImpossibleOperationError if type of requested device is not 'device'", async function () { await assert.rejects( async () => { @@ -91,7 +91,7 @@ export default function (context: Mocha.Context, testData: TestData) { ) }, (error) => { - assert(error instanceof ForbiddenOperationError) + assert(error instanceof ImpossibleOperationError) assert.strictEqual(error.status, 400) return true } diff --git a/services/device/test/operations/devices/device/websocket/post.spec.ts b/services/device/test/operations/devices/device/websocket/post.spec.ts index c8c10809..89ca6a57 100644 --- a/services/device/test/operations/devices/device/websocket/post.spec.ts +++ b/services/device/test/operations/devices/device/websocket/post.spec.ts @@ -2,7 +2,7 @@ import { deviceRepository } from '../../../../../src/database/repositories/devic import { postDevicesByDeviceIdWebsocket } from '../../../../../src/operations/devices' import { TestData } from '../../../../data/index.spec' import { addTest } from '../../../index.spec' -import { ForbiddenOperationError, MissingEntityError } from '@crosslab/service-common' +import { ImpossibleOperationError, MissingEntityError } from '@crosslab/service-common' import assert from 'assert' import Mocha from 'mocha' import * as sinon from 'sinon' @@ -57,7 +57,7 @@ export default function (context: Mocha.Context, testData: TestData) { addTest( suite, - "should throw a ForbiddenOperationError if the device is not of type 'device'", + "should throw a ImpossibleOperationError if the device is not of type 'device'", async function () { await assert.rejects( async () => { @@ -69,7 +69,7 @@ export default function (context: Mocha.Context, testData: TestData) { ) }, (error) => { - assert(error instanceof ForbiddenOperationError) + assert(error instanceof ImpossibleOperationError) assert.strictEqual(error.status, 400) return true } From d9165faf2a40ee6f81d0f93c52f64a6c0c9c7e43 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Tue, 25 Apr 2023 08:40:57 +0000 Subject: [PATCH 30/33] Prepare Merge --- .jobs.yml | 6 + .vscode/settings.json | 10 +- README.md | 7 +- clients/.vscode/settings.json | 28 +- clients/api/.vscode/settings.json | 25 +- clients/api/js/.vscode/settings.json | 25 +- clients/api/python/.vscode/settings.json | 25 +- .../python/src/crosslab/api_client/client.py | 33 + .../python/src/crosslab/api_client/schemas.py | 647 +++++++++++------- clients/api/python/tests/test_openapi.py | 190 ++++- clients/soa/.vscode/settings.json | 26 +- clients/soa/js/.vscode/settings.json | 25 +- clients/soa/python/.vscode/settings.json | 25 +- clients/soa_services/.vscode/settings.json | 24 +- .../.vscode/settings.json | 25 +- .../js/.vscode/settings.json | 25 +- .../python/.vscode/settings.json | 25 +- .../soa_services/file/.vscode/settings.json | 25 +- .../file/js/.vscode/settings.json | 25 +- .../file/python/.vscode/settings.json | 25 +- .../message/.vscode/settings.json | 25 +- .../message/js/.vscode/settings.json | 25 +- .../message/python/.vscode/settings.json | 25 +- .../soa_services/webcam/.vscode/settings.json | 25 +- .../webcam/js/.vscode/settings.json | 25 +- .../webcam/python/.vscode/settings.json | 25 +- helper/.vscode/settings.json | 24 +- .../.vscode/settings.json | 25 +- helper/dummy-device/.vscode/settings.json | 25 +- helper/dummy-device/js/.vscode/settings.json | 25 +- .../dummy-device/python/.vscode/settings.json | 25 +- .../.vscode/settings.json | 25 +- helper/tsdoc-theme/.vscode/settings.json | 25 +- integration-test/.vscode/settings.json | 25 +- services/.vscode/settings.json | 25 +- services/auth/.vscode/settings.json | 25 +- services/auth/README.md | 12 +- services/auth/addShebang.js | 4 + services/auth/package.json | 3 +- services/auth/scripts/test.sh | 1 + services/auth/src/index.ts | 2 - .../auth/test/operations/auth/get.spec.ts | 1 - .../deviceAuthenticationToken/post.spec.ts | 6 +- services/booking/.vscode/settings.json | 25 +- services/common/.vscode/settings.json | 25 +- services/device/.vscode/settings.json | 25 +- services/device/scripts/test.sh | 1 + services/experiment/.vscode/settings.json | 25 +- .../experiment/src/database/methods/create.ts | 1 - services/experiment/src/database/model.ts | 11 +- services/experiment/src/util/api.ts | 4 +- services/experiment/src/util/callbacks.ts | 19 +- .../experiment/src/util/connectionPlan.ts | 5 +- services/federation/.vscode/settings.json | 25 +- services/gateway/.vscode/settings.json | 25 +- services/openapi/.vscode/settings.json | 25 +- services/update/.vscode/settings.json | 25 +- 57 files changed, 728 insertions(+), 1187 deletions(-) create mode 100644 services/auth/addShebang.js create mode 120000 services/auth/scripts/test.sh create mode 120000 services/device/scripts/test.sh diff --git a/.jobs.yml b/.jobs.yml index 7d2b3ed9..617f543f 100644 --- a/.jobs.yml +++ b/.jobs.yml @@ -93,6 +93,9 @@ services/auth: - script: lint dependencies: - services/auth:build + - script: test + dependencies: + - services/auth:build services/booking: - script: build-spec @@ -117,6 +120,9 @@ services/device: - script: build-docker dependencies: - services/device:build + - script: test + dependencies: + - services/auth:build services/experiment: - script: build-spec diff --git a/.vscode/settings.json b/.vscode/settings.json index 37747357..c9275d21 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,21 +13,21 @@ "**/__pycache__": true, "**/*.egg-info": true, "**/build": true, - "**/lib": true, + // "**/lib": true, "**/app": true, "**/venv": true, "**/.packages": true, //begin generated - "clients/.vscode": true, "clients/api/.vscode": true, - "clients/soa/.vscode": true, - "clients/soa_services/.vscode": true, "clients/soa_services/electricalConnection/.vscode": true, "clients/soa_services/file/.vscode": true, "clients/soa_services/message/.vscode": true, + "clients/soa_services/.vscode": true, "clients/soa_services/webcam/.vscode": true, - "helper/.vscode": true, + "clients/soa/.vscode": true, + "clients/.vscode": true, "helper/dummy-device/.vscode": true, + "helper/.vscode": true, "services/.vscode": true, //end generated }, diff --git a/README.md b/README.md index 64e40fcb..4acc6748 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ The following table shows the status for all jobs in this repository. | helper/dummy-device/js | | | [![build](https://ci.goldi-labs.de/crosslab/main/helper/dummy-device/js/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/helper/dummy-device/js/dist/build.log) | [![lint](https://ci.goldi-labs.de/crosslab/main/helper/dummy-device/js/dist/lint.badge)](https://ci.goldi-labs.de/crosslab/main/helper/dummy-device/js/dist/lint.log) | | | | helper/dummy-device/python | | | [![build](https://ci.goldi-labs.de/crosslab/main/helper/dummy-device/python/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/helper/dummy-device/python/dist/build.log) | [![lint](https://ci.goldi-labs.de/crosslab/main/helper/dummy-device/python/dist/lint.badge)](https://ci.goldi-labs.de/crosslab/main/helper/dummy-device/python/dist/lint.log) | | | | services/common | | | [![build](https://ci.goldi-labs.de/crosslab/main/services/common/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/common/dist/build.log) | [![lint](https://ci.goldi-labs.de/crosslab/main/services/common/dist/lint.badge)](https://ci.goldi-labs.de/crosslab/main/services/common/dist/lint.log) | | | -| services/auth | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint-spec.log) | [![build](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build.log) | [![lint](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint.log) | | [![build-docker](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-docker.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-docker.log) | +| services/auth | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint-spec.log) | [![build](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build.log) | [![lint](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint.log) | [![test](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/test.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/test.log) | [![build-docker](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-docker.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-docker.log) | | services/booking | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/booking/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/booking/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/booking/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/booking/dist/lint-spec.log) | | | | | -| services/device | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/device/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/device/dist/lint-spec.log) | [![build](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build.log) | | | [![build-docker](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build-docker.badge)](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build-docker.log) | +| services/device | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/device/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/device/dist/lint-spec.log) | [![build](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build.log) | | [![test](https://ci.goldi-labs.de/crosslab/main/services/device/dist/test.badge)](https://ci.goldi-labs.de/crosslab/main/services/device/dist/test.log) | [![build-docker](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build-docker.badge)](https://ci.goldi-labs.de/crosslab/main/services/device/dist/build-docker.log) | | services/experiment | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/lint-spec.log) | [![build](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/build.log) | [![lint](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/lint.badge)](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/lint.log) | | [![build-docker](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/build-docker.badge)](https://ci.goldi-labs.de/crosslab/main/services/experiment/dist/build-docker.log) | | services/federation | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/federation/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/federation/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/federation/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/federation/dist/lint-spec.log) | [![build](https://ci.goldi-labs.de/crosslab/main/services/federation/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/federation/dist/build.log) | | | [![build-docker](https://ci.goldi-labs.de/crosslab/main/services/federation/dist/build-docker.badge)](https://ci.goldi-labs.de/crosslab/main/services/federation/dist/build-docker.log) | | services/update | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/update/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/update/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/update/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/update/dist/lint-spec.log) | [![build](https://ci.goldi-labs.de/crosslab/main/services/update/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/update/dist/build.log) | | | [![build-docker](https://ci.goldi-labs.de/crosslab/main/services/update/dist/build-docker.badge)](https://ci.goldi-labs.de/crosslab/main/services/update/dist/build-docker.log) | @@ -138,6 +138,7 @@ graph LR services/auth:build-spec[build-spec] services/auth:lint[lint] services/auth:lint-spec[lint-spec] + services/auth:test[test] end subgraph services/booking services/booking:build-spec[build-spec] @@ -152,6 +153,7 @@ graph LR services/device:build-docker[build-docker] services/device:build-spec[build-spec] services/device:lint-spec[lint-spec] + services/device:test[test] end subgraph services/experiment services/experiment:build[build] @@ -235,6 +237,7 @@ helper/python-test-helper --> clients/soa_services/webcam/python helper/tsdoc-theme --> clients/api/js services/auth --> clients/api/js services/auth --> integration-test +services/auth --> services/device services/auth --> services/openapi services/booking --> clients/api/js services/booking --> services/openapi diff --git a/clients/.vscode/settings.json b/clients/.vscode/settings.json index 6c57a59b..da5961ca 100644 --- a/clients/.vscode/settings.json +++ b/clients/.vscode/settings.json @@ -1,40 +1,18 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, "api/.vscode": true, - "soa/.vscode": true, - "soa_services/.vscode": true, "soa_services/electricalConnection/.vscode": true, "soa_services/file/.vscode": true, "soa_services/message/.vscode": true, + "soa_services/.vscode": true, "soa_services/webcam/.vscode": true, + "soa/.vscode": true, //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/api/.vscode/settings.json b/clients/api/.vscode/settings.json index f90817be..65755078 100644 --- a/clients/api/.vscode/settings.json +++ b/clients/api/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/api/js/.vscode/settings.json b/clients/api/js/.vscode/settings.json index f90817be..6c65abed 100644 --- a/clients/api/js/.vscode/settings.json +++ b/clients/api/js/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/api/python/.vscode/settings.json b/clients/api/python/.vscode/settings.json index 8f7703e3..8f646a93 100644 --- a/clients/api/python/.vscode/settings.json +++ b/clients/api/python/.vscode/settings.json @@ -16,33 +16,12 @@ ], "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/clients/api/python/src/crosslab/api_client/client.py b/clients/api/python/src/crosslab/api_client/client.py index d73f7e1c..5a2517b6 100644 --- a/clients/api/python/src/crosslab/api_client/client.py +++ b/clients/api/python/src/crosslab/api_client/client.py @@ -65,6 +65,8 @@ CreatePeerconnectionResponse, GetPeerconnectionResponse, DeletePeerconnectionResponse, + PatchPeerconnectionDeviceStatusRequest, + PatchPeerconnectionDeviceStatusResponse, ListExperimentsResponse, CreateExperimentRequest, CreateExperimentResponse, @@ -1160,6 +1162,37 @@ async def delete_peerconnection(self, url: str) -> DeletePeerconnectionResponse: return resp raise Exception(f"Unexpected status code: {status}") + async def patch_peerconnection_device_status(self, url: str, body: PatchPeerconnectionDeviceStatusRequest, device_url: str) -> PatchPeerconnectionDeviceStatusResponse: # noqa: E501 + """ + Sets the peerconnection status of a single device. + """ # noqa: E501 + if not self.BASE_URL: + raise Exception("No base url set") + + # match path to url schema + m = re.search(r'^('+re.escape(self.BASE_URL)+r')?\/?(peerconnections\/[^?]*?)(\/device_status)?$', url) + if m is None: + raise Exception("Invalid url") + valid_url = '/'+m.group(2)+'/device_status' + if valid_url.startswith('//'): + valid_url = valid_url[1:] + + # build query params + query_params: Dict[str, Union[List[str], str]] = {} + if device_url: + if isinstance(device_url, list): + query_params['device_url'] = device_url + else: + query_params['device_url'] = str(device_url) + + # make http call + status, resp = await self._fetch(valid_url, method="patch", body=body, params=query_params) + + # transform response + if status == 201: + return resp + raise Exception(f"Unexpected status code: {status}") + async def list_experiments(self, url: str = "/experiments") -> ListExperimentsResponse: # noqa: E501 """ List experiments diff --git a/clients/api/python/src/crosslab/api_client/schemas.py b/clients/api/python/src/crosslab/api_client/schemas.py index e331443b..4729073c 100644 --- a/clients/api/python/src/crosslab/api_client/schemas.py +++ b/clients/api/python/src/crosslab/api_client/schemas.py @@ -801,11 +801,11 @@ class ListDevicesResponse200Items(TypedDict): - type: Type of the device - owner """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["device", "group", "edge instantiable", "cloud instantiable"]] - owner: NotRequired[str] + type: Literal["device", "group", "edge instantiable", "cloud instantiable"] + owner: str ListDevicesResponse200: TypeAlias = List[ListDevicesResponse200Items] @@ -814,19 +814,61 @@ class ListDevicesResponse200Items(TypedDict): ListDevicesResponse: TypeAlias = ListDevicesResponse200 -class CreateDeviceRequestAlt1AnnouncedavailabilityItems(TypedDict): +class CreateDeviceRequestAlt1ServicesItems(TypedDict): """ Properties: + - serviceType + - serviceId + - serviceDirection """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] -class CreateDeviceRequestAlt1ServicesItems(TypedDict): +class CreateDeviceRequestAlt1(TypedDict): """ Properties: + - url: URL of the device + - name: Name of the device + - description: Extended description of the device, features, etc. + - type: Type of the device + - owner + - instantiateUrl + - services """ + url: str + name: str + description: NotRequired[str] + type: Literal["cloud instantiable"] + owner: str + instantiateUrl: NotRequired[str] + services: NotRequired[List[CreateDeviceRequestAlt1ServicesItems]] -class CreateDeviceRequestAlt1(TypedDict): +class CreateDeviceRequestAlt2AnnouncedavailabilityItems(TypedDict): + """ + Properties: + - start + - end + """ + start: NotRequired[str] + end: NotRequired[str] + + +class CreateDeviceRequestAlt2ServicesItems(TypedDict): + """ + Properties: + - serviceType + - serviceId + - serviceDirection + """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] + + +class CreateDeviceRequestAlt2(TypedDict): """ Properties: - url: URL of the device @@ -841,26 +883,30 @@ class CreateDeviceRequestAlt1(TypedDict): - experiment - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["device"]] - owner: NotRequired[str] + type: Literal["device"] + owner: str connected: NotRequired[bool] - announcedAvailability: NotRequired[List[CreateDeviceRequestAlt1AnnouncedavailabilityItems]] + announcedAvailability: NotRequired[List[CreateDeviceRequestAlt2AnnouncedavailabilityItems]] experiment: NotRequired[str] - services: NotRequired[List[CreateDeviceRequestAlt1ServicesItems]] + services: NotRequired[List[CreateDeviceRequestAlt2ServicesItems]] -class CreateDeviceRequestAlt2DevicesItems(TypedDict): +class CreateDeviceRequestAlt3ServicesItems(TypedDict): """ Properties: - - url: URL of the device + - serviceType + - serviceId + - serviceDirection """ - url: NotRequired[str] + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] -class CreateDeviceRequestAlt2(TypedDict): +class CreateDeviceRequestAlt3(TypedDict): """ Properties: - url: URL of the device @@ -868,17 +914,27 @@ class CreateDeviceRequestAlt2(TypedDict): - description: Extended description of the device, features, etc. - type: Type of the device - owner - - devices + - codeUrl + - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["group"]] - owner: NotRequired[str] - devices: NotRequired[List[CreateDeviceRequestAlt2DevicesItems]] + type: Literal["edge instantiable"] + owner: str + codeUrl: NotRequired[str] + services: NotRequired[List[CreateDeviceRequestAlt3ServicesItems]] -class CreateDeviceRequestAlt3(TypedDict): +class CreateDeviceRequestAlt4DevicesItems(TypedDict): + """ + Properties: + - url: URL of the device + """ + url: str + + +class CreateDeviceRequestAlt4(TypedDict): """ Properties: - url: URL of the device @@ -886,17 +942,32 @@ class CreateDeviceRequestAlt3(TypedDict): - description: Extended description of the device, features, etc. - type: Type of the device - owner - - instantiate_url + - devices """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["cloud instantiable"]] - owner: NotRequired[str] - instantiate_url: NotRequired[str] + type: Literal["group"] + owner: str + devices: List[CreateDeviceRequestAlt4DevicesItems] -class CreateDeviceRequestAlt4(TypedDict): +CreateDeviceRequest = Union[CreateDeviceRequestAlt1, CreateDeviceRequestAlt2, CreateDeviceRequestAlt3, CreateDeviceRequestAlt4] + + +class CreateDeviceResponse201Alt1ServicesItems(TypedDict): + """ + Properties: + - serviceType + - serviceId + - serviceDirection + """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] + + +class CreateDeviceResponse201Alt1(TypedDict): """ Properties: - url: URL of the device @@ -904,20 +975,19 @@ class CreateDeviceRequestAlt4(TypedDict): - description: Extended description of the device, features, etc. - type: Type of the device - owner - - code_url + - instantiateUrl + - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["edge instantiable"]] - owner: NotRequired[str] - code_url: NotRequired[str] - - -CreateDeviceRequest = Union[CreateDeviceRequestAlt1, CreateDeviceRequestAlt2, CreateDeviceRequestAlt3, CreateDeviceRequestAlt4] + type: Literal["cloud instantiable"] + owner: str + instantiateUrl: NotRequired[str] + services: NotRequired[List[CreateDeviceResponse201Alt1ServicesItems]] -class CreateDeviceResponse201Alt1AnnouncedavailabilityItems(TypedDict): +class CreateDeviceResponse201Alt2AnnouncedavailabilityItems(TypedDict): """ Properties: - start @@ -927,13 +997,19 @@ class CreateDeviceResponse201Alt1AnnouncedavailabilityItems(TypedDict): end: NotRequired[str] -class CreateDeviceResponse201Alt1ServicesItems(TypedDict): +class CreateDeviceResponse201Alt2ServicesItems(TypedDict): """ Properties: + - serviceType + - serviceId + - serviceDirection """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] -class CreateDeviceResponse201Alt1(TypedDict): +class CreateDeviceResponse201Alt2(TypedDict): """ Properties: - url: URL of the device @@ -948,26 +1024,30 @@ class CreateDeviceResponse201Alt1(TypedDict): - experiment - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["device"]] - owner: NotRequired[str] + type: Literal["device"] + owner: str connected: NotRequired[bool] - announcedAvailability: NotRequired[List[CreateDeviceResponse201Alt1AnnouncedavailabilityItems]] + announcedAvailability: NotRequired[List[CreateDeviceResponse201Alt2AnnouncedavailabilityItems]] experiment: NotRequired[str] - services: NotRequired[List[CreateDeviceResponse201Alt1ServicesItems]] + services: NotRequired[List[CreateDeviceResponse201Alt2ServicesItems]] -class CreateDeviceResponse201Alt2DevicesItems(TypedDict): +class CreateDeviceResponse201Alt3ServicesItems(TypedDict): """ Properties: - - url: URL of the device + - serviceType + - serviceId + - serviceDirection """ - url: NotRequired[str] + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] -class CreateDeviceResponse201Alt2(TypedDict): +class CreateDeviceResponse201Alt3(TypedDict): """ Properties: - url: URL of the device @@ -975,32 +1055,24 @@ class CreateDeviceResponse201Alt2(TypedDict): - description: Extended description of the device, features, etc. - type: Type of the device - owner - - devices + - codeUrl + - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["group"]] - owner: NotRequired[str] - devices: NotRequired[List[CreateDeviceResponse201Alt2DevicesItems]] + type: Literal["edge instantiable"] + owner: str + codeUrl: NotRequired[str] + services: NotRequired[List[CreateDeviceResponse201Alt3ServicesItems]] -class CreateDeviceResponse201Alt3(TypedDict): +class CreateDeviceResponse201Alt4DevicesItems(TypedDict): """ Properties: - url: URL of the device - - name: Name of the device - - description: Extended description of the device, features, etc. - - type: Type of the device - - owner - - instantiate_url """ - url: NotRequired[str] - name: NotRequired[str] - description: NotRequired[str] - type: NotRequired[Literal["cloud instantiable"]] - owner: NotRequired[str] - instantiate_url: NotRequired[str] + url: str class CreateDeviceResponse201Alt4(TypedDict): @@ -1011,14 +1083,14 @@ class CreateDeviceResponse201Alt4(TypedDict): - description: Extended description of the device, features, etc. - type: Type of the device - owner - - code_url + - devices """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["edge instantiable"]] - owner: NotRequired[str] - code_url: NotRequired[str] + type: Literal["group"] + owner: str + devices: List[CreateDeviceResponse201Alt4DevicesItems] CreateDeviceResponse201 = Union[CreateDeviceResponse201Alt1, CreateDeviceResponse201Alt2, CreateDeviceResponse201Alt3, CreateDeviceResponse201Alt4] @@ -1027,7 +1099,39 @@ class CreateDeviceResponse201Alt4(TypedDict): CreateDeviceResponse: TypeAlias = CreateDeviceResponse201 -class GetDeviceResponse200Alt1AnnouncedavailabilityItems(TypedDict): +class GetDeviceResponse200Alt1ServicesItems(TypedDict): + """ + Properties: + - serviceType + - serviceId + - serviceDirection + """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] + + +class GetDeviceResponse200Alt1(TypedDict): + """ + Properties: + - url: URL of the device + - name: Name of the device + - description: Extended description of the device, features, etc. + - type: Type of the device + - owner + - instantiateUrl + - services + """ + url: str + name: str + description: NotRequired[str] + type: Literal["cloud instantiable"] + owner: str + instantiateUrl: NotRequired[str] + services: NotRequired[List[GetDeviceResponse200Alt1ServicesItems]] + + +class GetDeviceResponse200Alt2AnnouncedavailabilityItems(TypedDict): """ Properties: - start @@ -1037,13 +1141,19 @@ class GetDeviceResponse200Alt1AnnouncedavailabilityItems(TypedDict): end: NotRequired[str] -class GetDeviceResponse200Alt1ServicesItems(TypedDict): +class GetDeviceResponse200Alt2ServicesItems(TypedDict): """ Properties: + - serviceType + - serviceId + - serviceDirection """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] -class GetDeviceResponse200Alt1(TypedDict): +class GetDeviceResponse200Alt2(TypedDict): """ Properties: - url: URL of the device @@ -1058,26 +1168,30 @@ class GetDeviceResponse200Alt1(TypedDict): - experiment - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["device"]] - owner: NotRequired[str] + type: Literal["device"] + owner: str connected: NotRequired[bool] - announcedAvailability: NotRequired[List[GetDeviceResponse200Alt1AnnouncedavailabilityItems]] + announcedAvailability: NotRequired[List[GetDeviceResponse200Alt2AnnouncedavailabilityItems]] experiment: NotRequired[str] - services: NotRequired[List[GetDeviceResponse200Alt1ServicesItems]] + services: NotRequired[List[GetDeviceResponse200Alt2ServicesItems]] -class GetDeviceResponse200Alt2DevicesItems(TypedDict): +class GetDeviceResponse200Alt3ServicesItems(TypedDict): """ Properties: - - url: URL of the device + - serviceType + - serviceId + - serviceDirection """ - url: NotRequired[str] + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] -class GetDeviceResponse200Alt2(TypedDict): +class GetDeviceResponse200Alt3(TypedDict): """ Properties: - url: URL of the device @@ -1085,32 +1199,24 @@ class GetDeviceResponse200Alt2(TypedDict): - description: Extended description of the device, features, etc. - type: Type of the device - owner - - devices + - codeUrl + - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["group"]] - owner: NotRequired[str] - devices: NotRequired[List[GetDeviceResponse200Alt2DevicesItems]] + type: Literal["edge instantiable"] + owner: str + codeUrl: NotRequired[str] + services: NotRequired[List[GetDeviceResponse200Alt3ServicesItems]] -class GetDeviceResponse200Alt3(TypedDict): +class GetDeviceResponse200Alt4DevicesItems(TypedDict): """ Properties: - url: URL of the device - - name: Name of the device - - description: Extended description of the device, features, etc. - - type: Type of the device - - owner - - instantiate_url """ - url: NotRequired[str] - name: NotRequired[str] - description: NotRequired[str] - type: NotRequired[Literal["cloud instantiable"]] - owner: NotRequired[str] - instantiate_url: NotRequired[str] + url: str class GetDeviceResponse200Alt4(TypedDict): @@ -1121,14 +1227,14 @@ class GetDeviceResponse200Alt4(TypedDict): - description: Extended description of the device, features, etc. - type: Type of the device - owner - - code_url + - devices """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["edge instantiable"]] - owner: NotRequired[str] - code_url: NotRequired[str] + type: Literal["group"] + owner: str + devices: List[GetDeviceResponse200Alt4DevicesItems] GetDeviceResponse200 = Union[GetDeviceResponse200Alt1, GetDeviceResponse200Alt2, GetDeviceResponse200Alt3, GetDeviceResponse200Alt4] @@ -1137,110 +1243,148 @@ class GetDeviceResponse200Alt4(TypedDict): GetDeviceResponse: TypeAlias = GetDeviceResponse200 -class UpdateDeviceRequestAlt1AnnouncedavailabilityItems(TypedDict): - """ - Properties: - """ - - class UpdateDeviceRequestAlt1ServicesItems(TypedDict): """ Properties: + - serviceType + - serviceId + - serviceDirection """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] class UpdateDeviceRequestAlt1(TypedDict): """ Properties: - - url: URL of the device - name: Name of the device - description: Extended description of the device, features, etc. - type: Type of the device - - owner - - connected: If true, the device is connected to the service and can be used. - - - announcedAvailability: A list of time slots that the maintainer of the device announced it is available - - - experiment + - instantiateUrl - services """ - url: NotRequired[str] name: NotRequired[str] description: NotRequired[str] - type: NotRequired[Literal["device"]] - owner: NotRequired[str] - connected: NotRequired[bool] - announcedAvailability: NotRequired[List[UpdateDeviceRequestAlt1AnnouncedavailabilityItems]] - experiment: NotRequired[str] + type: Literal["cloud instantiable"] + instantiateUrl: NotRequired[str] services: NotRequired[List[UpdateDeviceRequestAlt1ServicesItems]] -class UpdateDeviceRequestAlt2DevicesItems(TypedDict): +class UpdateDeviceRequestAlt2ServicesItems(TypedDict): """ Properties: - - url: URL of the device + - serviceType + - serviceId + - serviceDirection """ - url: NotRequired[str] + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] class UpdateDeviceRequestAlt2(TypedDict): """ Properties: - - url: URL of the device - name: Name of the device - description: Extended description of the device, features, etc. - type: Type of the device - - owner - - devices + - experiment + - services """ - url: NotRequired[str] name: NotRequired[str] description: NotRequired[str] - type: NotRequired[Literal["group"]] - owner: NotRequired[str] - devices: NotRequired[List[UpdateDeviceRequestAlt2DevicesItems]] + type: Literal["device"] + experiment: NotRequired[str] + services: NotRequired[List[UpdateDeviceRequestAlt2ServicesItems]] + + +class UpdateDeviceRequestAlt3ServicesItems(TypedDict): + """ + Properties: + - serviceType + - serviceId + - serviceDirection + """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] class UpdateDeviceRequestAlt3(TypedDict): """ Properties: - - url: URL of the device - name: Name of the device - description: Extended description of the device, features, etc. - type: Type of the device - - owner - - instantiate_url + - codeUrl + - services """ - url: NotRequired[str] name: NotRequired[str] description: NotRequired[str] - type: NotRequired[Literal["cloud instantiable"]] - owner: NotRequired[str] - instantiate_url: NotRequired[str] + type: Literal["edge instantiable"] + codeUrl: NotRequired[str] + services: NotRequired[List[UpdateDeviceRequestAlt3ServicesItems]] -class UpdateDeviceRequestAlt4(TypedDict): +class UpdateDeviceRequestAlt4DevicesItems(TypedDict): """ Properties: - url: URL of the device + """ + url: str + + +class UpdateDeviceRequestAlt4(TypedDict): + """ + Properties: - name: Name of the device - description: Extended description of the device, features, etc. - type: Type of the device - - owner - - code_url + - devices """ - url: NotRequired[str] name: NotRequired[str] description: NotRequired[str] - type: NotRequired[Literal["edge instantiable"]] - owner: NotRequired[str] - code_url: NotRequired[str] + type: Literal["group"] + devices: NotRequired[List[UpdateDeviceRequestAlt4DevicesItems]] UpdateDeviceRequest = Union[UpdateDeviceRequestAlt1, UpdateDeviceRequestAlt2, UpdateDeviceRequestAlt3, UpdateDeviceRequestAlt4] -class UpdateDeviceResponse200Alt1AnnouncedavailabilityItems(TypedDict): +class UpdateDeviceResponse200Alt1ServicesItems(TypedDict): + """ + Properties: + - serviceType + - serviceId + - serviceDirection + """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] + + +class UpdateDeviceResponse200Alt1(TypedDict): + """ + Properties: + - url: URL of the device + - name: Name of the device + - description: Extended description of the device, features, etc. + - type: Type of the device + - owner + - instantiateUrl + - services + """ + url: str + name: str + description: NotRequired[str] + type: Literal["cloud instantiable"] + owner: str + instantiateUrl: NotRequired[str] + services: NotRequired[List[UpdateDeviceResponse200Alt1ServicesItems]] + + +class UpdateDeviceResponse200Alt2AnnouncedavailabilityItems(TypedDict): """ Properties: - start @@ -1250,13 +1394,19 @@ class UpdateDeviceResponse200Alt1AnnouncedavailabilityItems(TypedDict): end: NotRequired[str] -class UpdateDeviceResponse200Alt1ServicesItems(TypedDict): +class UpdateDeviceResponse200Alt2ServicesItems(TypedDict): """ Properties: + - serviceType + - serviceId + - serviceDirection """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] -class UpdateDeviceResponse200Alt1(TypedDict): +class UpdateDeviceResponse200Alt2(TypedDict): """ Properties: - url: URL of the device @@ -1271,26 +1421,30 @@ class UpdateDeviceResponse200Alt1(TypedDict): - experiment - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["device"]] - owner: NotRequired[str] + type: Literal["device"] + owner: str connected: NotRequired[bool] - announcedAvailability: NotRequired[List[UpdateDeviceResponse200Alt1AnnouncedavailabilityItems]] + announcedAvailability: NotRequired[List[UpdateDeviceResponse200Alt2AnnouncedavailabilityItems]] experiment: NotRequired[str] - services: NotRequired[List[UpdateDeviceResponse200Alt1ServicesItems]] + services: NotRequired[List[UpdateDeviceResponse200Alt2ServicesItems]] -class UpdateDeviceResponse200Alt2DevicesItems(TypedDict): +class UpdateDeviceResponse200Alt3ServicesItems(TypedDict): """ Properties: - - url: URL of the device + - serviceType + - serviceId + - serviceDirection """ - url: NotRequired[str] + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] -class UpdateDeviceResponse200Alt2(TypedDict): +class UpdateDeviceResponse200Alt3(TypedDict): """ Properties: - url: URL of the device @@ -1298,32 +1452,24 @@ class UpdateDeviceResponse200Alt2(TypedDict): - description: Extended description of the device, features, etc. - type: Type of the device - owner - - devices + - codeUrl + - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["group"]] - owner: NotRequired[str] - devices: NotRequired[List[UpdateDeviceResponse200Alt2DevicesItems]] + type: Literal["edge instantiable"] + owner: str + codeUrl: NotRequired[str] + services: NotRequired[List[UpdateDeviceResponse200Alt3ServicesItems]] -class UpdateDeviceResponse200Alt3(TypedDict): +class UpdateDeviceResponse200Alt4DevicesItems(TypedDict): """ Properties: - url: URL of the device - - name: Name of the device - - description: Extended description of the device, features, etc. - - type: Type of the device - - owner - - instantiate_url """ - url: NotRequired[str] - name: NotRequired[str] - description: NotRequired[str] - type: NotRequired[Literal["cloud instantiable"]] - owner: NotRequired[str] - instantiate_url: NotRequired[str] + url: str class UpdateDeviceResponse200Alt4(TypedDict): @@ -1334,14 +1480,14 @@ class UpdateDeviceResponse200Alt4(TypedDict): - description: Extended description of the device, features, etc. - type: Type of the device - owner - - code_url + - devices """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["edge instantiable"]] - owner: NotRequired[str] - code_url: NotRequired[str] + type: Literal["group"] + owner: str + devices: List[UpdateDeviceResponse200Alt4DevicesItems] UpdateDeviceResponse200 = Union[UpdateDeviceResponse200Alt1, UpdateDeviceResponse200Alt2, UpdateDeviceResponse200Alt3, UpdateDeviceResponse200Alt4] @@ -1366,7 +1512,13 @@ class InstantiateDeviceResponse201InstanceAnnouncedavailabilityItems(TypedDict): class InstantiateDeviceResponse201InstanceServicesItems(TypedDict): """ Properties: + - serviceType + - serviceId + - serviceDirection """ + serviceType: NotRequired[str] + serviceId: NotRequired[str] + serviceDirection: NotRequired[Literal["consumer", "producer", "prosumer"]] class InstantiateDeviceResponse201Instance(TypedDict): @@ -1384,11 +1536,11 @@ class InstantiateDeviceResponse201Instance(TypedDict): - experiment - services """ - url: NotRequired[str] - name: NotRequired[str] + url: str + name: str description: NotRequired[str] - type: NotRequired[Literal["device"]] - owner: NotRequired[str] + type: Literal["device"] + owner: str connected: NotRequired[bool] announcedAvailability: NotRequired[List[InstantiateDeviceResponse201InstanceAnnouncedavailabilityItems]] experiment: NotRequired[str] @@ -1401,8 +1553,8 @@ class InstantiateDeviceResponse201(TypedDict): - instance - deviceToken """ - instance: NotRequired[InstantiateDeviceResponse201Instance] - deviceToken: NotRequired[str] + instance: InstantiateDeviceResponse201Instance + deviceToken: str InstantiateDeviceResponse: TypeAlias = InstantiateDeviceResponse201 @@ -1470,7 +1622,7 @@ class SendSignalingMessageRequestAlt1(TypedDict): """ messageType: Literal["command"] command: Literal["createPeerconnection"] - connectionType: Literal["webrtc", "websocket"] + connectionType: Literal["webrtc", "websocket", "local"] connectionUrl: str services: List[SendSignalingMessageRequestAlt1ServicesItems] tiebreaker: bool @@ -1520,17 +1672,21 @@ class ListPeerconnectionsResponse200ItemsDevicesItems(TypedDict): Properties: - url: URL of the device """ - url: NotRequired[str] + url: str class ListPeerconnectionsResponse200Items(TypedDict): """ Properties: - url: URL of the peerconnection + - type: Type of the peerconnection + - status: The status of the peerconnection. - devices """ - url: NotRequired[str] - devices: NotRequired[List[ListPeerconnectionsResponse200ItemsDevicesItems]] + url: str + type: Literal["local", "webrtc"] + status: NotRequired[Literal["new", "connecting", "connected", "disconnected", "failed", "closed"]] + devices: List[ListPeerconnectionsResponse200ItemsDevicesItems] ListPeerconnectionsResponse200: TypeAlias = List[ListPeerconnectionsResponse200Items] @@ -1546,9 +1702,9 @@ class CreatePeerconnectionRequestDevicesItemsConfigServicesItems(TypedDict): - serviceId - remoteServiceId """ - serviceType: NotRequired[str] - serviceId: NotRequired[str] - remoteServiceId: NotRequired[str] + serviceType: str + serviceId: str + remoteServiceId: str class CreatePeerconnectionRequestDevicesItemsConfig(TypedDict): @@ -1565,7 +1721,7 @@ class CreatePeerconnectionRequestDevicesItems(TypedDict): - url: URL of the device - config """ - url: NotRequired[str] + url: str config: NotRequired[CreatePeerconnectionRequestDevicesItemsConfig] @@ -1573,12 +1729,14 @@ class CreatePeerconnectionRequest(TypedDict): """ Properties: - url: URL of the peerconnection - - devices + - type: Type of the peerconnection - status: The status of the peerconnection. + - devices """ - url: NotRequired[str] - devices: NotRequired[List[CreatePeerconnectionRequestDevicesItems]] - status: NotRequired[Literal["waiting-for-devices", "connected", "failed", "closed"]] + url: str + type: Literal["local", "webrtc"] + status: NotRequired[Literal["new", "connecting", "connected", "disconnected", "failed", "closed"]] + devices: List[CreatePeerconnectionRequestDevicesItems] class CreatePeerconnectionResponse201DevicesItemsConfigServicesItems(TypedDict): @@ -1588,9 +1746,9 @@ class CreatePeerconnectionResponse201DevicesItemsConfigServicesItems(TypedDict): - serviceId - remoteServiceId """ - serviceType: NotRequired[str] - serviceId: NotRequired[str] - remoteServiceId: NotRequired[str] + serviceType: str + serviceId: str + remoteServiceId: str class CreatePeerconnectionResponse201DevicesItemsConfig(TypedDict): @@ -1607,7 +1765,7 @@ class CreatePeerconnectionResponse201DevicesItems(TypedDict): - url: URL of the device - config """ - url: NotRequired[str] + url: str config: NotRequired[CreatePeerconnectionResponse201DevicesItemsConfig] @@ -1615,12 +1773,14 @@ class CreatePeerconnectionResponse201(TypedDict): """ Properties: - url: URL of the peerconnection - - devices + - type: Type of the peerconnection - status: The status of the peerconnection. + - devices """ - url: NotRequired[str] - devices: NotRequired[List[CreatePeerconnectionResponse201DevicesItems]] - status: NotRequired[Literal["waiting-for-devices", "connected", "failed", "closed"]] + url: str + type: Literal["local", "webrtc"] + status: NotRequired[Literal["new", "connecting", "connected", "disconnected", "failed", "closed"]] + devices: List[CreatePeerconnectionResponse201DevicesItems] class CreatePeerconnectionResponse202DevicesItemsConfigServicesItems(TypedDict): @@ -1630,9 +1790,9 @@ class CreatePeerconnectionResponse202DevicesItemsConfigServicesItems(TypedDict): - serviceId - remoteServiceId """ - serviceType: NotRequired[str] - serviceId: NotRequired[str] - remoteServiceId: NotRequired[str] + serviceType: str + serviceId: str + remoteServiceId: str class CreatePeerconnectionResponse202DevicesItemsConfig(TypedDict): @@ -1649,7 +1809,7 @@ class CreatePeerconnectionResponse202DevicesItems(TypedDict): - url: URL of the device - config """ - url: NotRequired[str] + url: str config: NotRequired[CreatePeerconnectionResponse202DevicesItemsConfig] @@ -1657,12 +1817,14 @@ class CreatePeerconnectionResponse202(TypedDict): """ Properties: - url: URL of the peerconnection - - devices + - type: Type of the peerconnection - status: The status of the peerconnection. + - devices """ - url: NotRequired[str] - devices: NotRequired[List[CreatePeerconnectionResponse202DevicesItems]] - status: NotRequired[Literal["waiting-for-devices", "connected", "failed", "closed"]] + url: str + type: Literal["local", "webrtc"] + status: NotRequired[Literal["new", "connecting", "connected", "disconnected", "failed", "closed"]] + devices: List[CreatePeerconnectionResponse202DevicesItems] CreatePeerconnectionResponse: TypeAlias = Union[CreatePeerconnectionResponse201, CreatePeerconnectionResponse202] @@ -1675,9 +1837,9 @@ class GetPeerconnectionResponse200DevicesItemsConfigServicesItems(TypedDict): - serviceId - remoteServiceId """ - serviceType: NotRequired[str] - serviceId: NotRequired[str] - remoteServiceId: NotRequired[str] + serviceType: str + serviceId: str + remoteServiceId: str class GetPeerconnectionResponse200DevicesItemsConfig(TypedDict): @@ -1694,7 +1856,7 @@ class GetPeerconnectionResponse200DevicesItems(TypedDict): - url: URL of the device - config """ - url: NotRequired[str] + url: str config: NotRequired[GetPeerconnectionResponse200DevicesItemsConfig] @@ -1702,12 +1864,14 @@ class GetPeerconnectionResponse200(TypedDict): """ Properties: - url: URL of the peerconnection - - devices + - type: Type of the peerconnection - status: The status of the peerconnection. + - devices """ - url: NotRequired[str] - devices: NotRequired[List[GetPeerconnectionResponse200DevicesItems]] - status: NotRequired[Literal["waiting-for-devices", "connected", "failed", "closed"]] + url: str + type: Literal["local", "webrtc"] + status: NotRequired[Literal["new", "connecting", "connected", "disconnected", "failed", "closed"]] + devices: List[GetPeerconnectionResponse200DevicesItems] GetPeerconnectionResponse: TypeAlias = GetPeerconnectionResponse200 @@ -1716,6 +1880,17 @@ class GetPeerconnectionResponse200(TypedDict): DeletePeerconnectionResponse: TypeAlias = None +class PatchPeerconnectionDeviceStatusRequest(TypedDict): + """ + Properties: + - status: The status of the peerconnection. + """ + status: Literal["new", "connecting", "connected", "disconnected", "failed", "closed"] + + +PatchPeerconnectionDeviceStatusResponse: TypeAlias = None + + class ListExperimentsResponse200Items(TypedDict): """ Properties: diff --git a/clients/api/python/tests/test_openapi.py b/clients/api/python/tests/test_openapi.py index f8532887..14d24f1b 100644 --- a/clients/api/python/tests/test_openapi.py +++ b/clients/api/python/tests/test_openapi.py @@ -3830,28 +3830,28 @@ async def test_list_devices(aioresponses: aioresponses): parameter_list = [{}, ] for parameters in parameter_list: - response_200_dict = json.loads(r'[{"description":"occaecat ut non anim","owner":"http://XtyFMjWKLqVNOjoFVOCibGChfLnTd.elheA5xrKYP,KYInBcyGXAo7fWTRAFLv-I66+UEa11nOnUW,yrp7vU8tJDvqx-FBcm","url":"https://gUzGKHPeV.xtseja4ThHmONE6IMx"},{"description":"officia nisi ut","name":"ad amet dolore Duis","url":"https://xuSaiEaHtcvtcAzTVACnzItZUP.dpbsi.4CSbCelm2XPG6GJifZP5BwV","type":"cloud instantiable","owner":"http://knWGbtFvjEZogFuZq.jnbimyOtjLoxNnW04vVg+28XxLvtiBbTVsIXxMSxfV-cnpmwROVBavvKOxqv7Q"},{"description":"amet eu labore","url":"https://wrEF.iaf.vje-57RTm9JYGspOOJfsTdt0qLvKg914AbmBdlJfKZA4BFoJ","name":"sint cupidatat ipsum pariatur dolore","type":"device","owner":"http://NOdjkLvvuy.fihbxtyikUqV-5dwSkcBP+E4deORAAG2KGBsiq"}]') + response_200_dict = json.loads(r'[{"url":"https://CBBZavgAmnNDP.cozaaKD+VaFn-J2Ta4Dp9BeG8","type":"edge instantiable","name":"non velit minim dolore","owner":"https://RUz.umOAmQVVxIGHaSFxPN7ZkMCyH20hZFJ2xhFFyvqhjswohpHuSKDsWRPbLDobXP"}]') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.list_devices(**parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'[{"description":"occaecat ut non anim","owner":"http://XtyFMjWKLqVNOjoFVOCibGChfLnTd.elheA5xrKYP,KYInBcyGXAo7fWTRAFLv-I66+UEa11nOnUW,yrp7vU8tJDvqx-FBcm","url":"https://gUzGKHPeV.xtseja4ThHmONE6IMx"},{"description":"officia nisi ut","name":"ad amet dolore Duis","url":"https://xuSaiEaHtcvtcAzTVACnzItZUP.dpbsi.4CSbCelm2XPG6GJifZP5BwV","type":"cloud instantiable","owner":"http://knWGbtFvjEZogFuZq.jnbimyOtjLoxNnW04vVg+28XxLvtiBbTVsIXxMSxfV-cnpmwROVBavvKOxqv7Q"},{"description":"amet eu labore","url":"https://wrEF.iaf.vje-57RTm9JYGspOOJfsTdt0qLvKg914AbmBdlJfKZA4BFoJ","name":"sint cupidatat ipsum pariatur dolore","type":"device","owner":"http://NOdjkLvvuy.fihbxtyikUqV-5dwSkcBP+E4deORAAG2KGBsiq"}]') + response_200_dict = json.loads(r'[{"url":"https://CBBZavgAmnNDP.cozaaKD+VaFn-J2Ta4Dp9BeG8","type":"edge instantiable","name":"non velit minim dolore","owner":"https://RUz.umOAmQVVxIGHaSFxPN7ZkMCyH20hZFJ2xhFFyvqhjswohpHuSKDsWRPbLDobXP"}]') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.list_devices(url=url, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'[{"description":"occaecat ut non anim","owner":"http://XtyFMjWKLqVNOjoFVOCibGChfLnTd.elheA5xrKYP,KYInBcyGXAo7fWTRAFLv-I66+UEa11nOnUW,yrp7vU8tJDvqx-FBcm","url":"https://gUzGKHPeV.xtseja4ThHmONE6IMx"},{"description":"officia nisi ut","name":"ad amet dolore Duis","url":"https://xuSaiEaHtcvtcAzTVACnzItZUP.dpbsi.4CSbCelm2XPG6GJifZP5BwV","type":"cloud instantiable","owner":"http://knWGbtFvjEZogFuZq.jnbimyOtjLoxNnW04vVg+28XxLvtiBbTVsIXxMSxfV-cnpmwROVBavvKOxqv7Q"},{"description":"amet eu labore","url":"https://wrEF.iaf.vje-57RTm9JYGspOOJfsTdt0qLvKg914AbmBdlJfKZA4BFoJ","name":"sint cupidatat ipsum pariatur dolore","type":"device","owner":"http://NOdjkLvvuy.fihbxtyikUqV-5dwSkcBP+E4deORAAG2KGBsiq"}]') + response_200_dict = json.loads(r'[{"url":"https://CBBZavgAmnNDP.cozaaKD+VaFn-J2Ta4Dp9BeG8","type":"edge instantiable","name":"non velit minim dolore","owner":"https://RUz.umOAmQVVxIGHaSFxPN7ZkMCyH20hZFJ2xhFFyvqhjswohpHuSKDsWRPbLDobXP"}]') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.list_devices(url=url_variant, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'[{"description":"occaecat ut non anim","owner":"http://XtyFMjWKLqVNOjoFVOCibGChfLnTd.elheA5xrKYP,KYInBcyGXAo7fWTRAFLv-I66+UEa11nOnUW,yrp7vU8tJDvqx-FBcm","url":"https://gUzGKHPeV.xtseja4ThHmONE6IMx"},{"description":"officia nisi ut","name":"ad amet dolore Duis","url":"https://xuSaiEaHtcvtcAzTVACnzItZUP.dpbsi.4CSbCelm2XPG6GJifZP5BwV","type":"cloud instantiable","owner":"http://knWGbtFvjEZogFuZq.jnbimyOtjLoxNnW04vVg+28XxLvtiBbTVsIXxMSxfV-cnpmwROVBavvKOxqv7Q"},{"description":"amet eu labore","url":"https://wrEF.iaf.vje-57RTm9JYGspOOJfsTdt0qLvKg914AbmBdlJfKZA4BFoJ","name":"sint cupidatat ipsum pariatur dolore","type":"device","owner":"http://NOdjkLvvuy.fihbxtyikUqV-5dwSkcBP+E4deORAAG2KGBsiq"}]') + response_200_dict = json.loads(r'[{"url":"https://CBBZavgAmnNDP.cozaaKD+VaFn-J2Ta4Dp9BeG8","type":"edge instantiable","name":"non velit minim dolore","owner":"https://RUz.umOAmQVVxIGHaSFxPN7ZkMCyH20hZFJ2xhFFyvqhjswohpHuSKDsWRPbLDobXP"}]') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.list_devices(url=full_url, **parameters) @@ -3984,33 +3984,33 @@ async def test_create_device(aioresponses: aioresponses): url_variant = r'devices' full_url = BASE_URL+r'/devices' - request = json.loads(r'{"services":[],"url":"https://FFtBZqePJevWvqANceH.erzuirQaTbcwUTzpisvYDrbm0JMrsFw.-U1iS5kUOo","type":"device","connected":true,"owner":"https://mDCjpDPqCPPtDeHBrJuRtfOZdAkcLQgiM.kjDA0FCmSOocI6lV.q9RAXULVivUlme.Yb+A5VglKZF9jsM33IUv5MmtYkt4tbqo7-gGC4","description":"consequat id commodo","name":"amet Duis eiusmod dolor deserunt","experiment":"https://yZjFsGlZmXSOaJmchy.ezuSwTSEZ9RaYnbjr-R86Gm5bddW7BbgjWvaia3qfQMtJd,JFhTVyi7xYNvwoq.FegAtFIqvVB","announcedAvailability":[{"repeat":{"frequency":"DAILY","until":"1996-05-09T01:35:51.0Z"}}]}') + request = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') parameter_list = [{"changedUrl": "test_string", }, {}, ] for parameters in parameter_list: - response_201_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_201_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.create_device(body=request, **parameters) assert normalize_result(resp) == normalize_result(response_201_dict) for parameters in parameter_list: - response_201_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_201_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.create_device(url=url, body=request, **parameters) assert normalize_result(resp) == normalize_result(response_201_dict) for parameters in parameter_list: - response_201_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_201_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.create_device(url=url_variant, body=request, **parameters) assert normalize_result(resp) == normalize_result(response_201_dict) for parameters in parameter_list: - response_201_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_201_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.create_device(url=full_url, body=request, **parameters) @@ -4146,21 +4146,21 @@ async def test_get_device(aioresponses: aioresponses): parameter_list = [{"flat_group": True, }, {}, ] for parameters in parameter_list: - response_200_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_200_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.get_device(url=url, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_200_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.get_device(url=url_variant, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_200_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.get_device(url=full_url, **parameters) @@ -4263,26 +4263,26 @@ async def test_update_device(aioresponses: aioresponses): url_variant = r'devices/c799cc2e-cdc5-4143-973a-6f56a5afa82c' full_url = BASE_URL+r'/devices/c799cc2e-cdc5-4143-973a-6f56a5afa82c' - request = json.loads(r'{"services":[],"url":"https://FFtBZqePJevWvqANceH.erzuirQaTbcwUTzpisvYDrbm0JMrsFw.-U1iS5kUOo","type":"device","connected":true,"owner":"https://mDCjpDPqCPPtDeHBrJuRtfOZdAkcLQgiM.kjDA0FCmSOocI6lV.q9RAXULVivUlme.Yb+A5VglKZF9jsM33IUv5MmtYkt4tbqo7-gGC4","description":"consequat id commodo","name":"amet Duis eiusmod dolor deserunt","experiment":"https://yZjFsGlZmXSOaJmchy.ezuSwTSEZ9RaYnbjr-R86Gm5bddW7BbgjWvaia3qfQMtJd,JFhTVyi7xYNvwoq.FegAtFIqvVB","announcedAvailability":[{"repeat":{"frequency":"DAILY","until":"1996-05-09T01:35:51.0Z"}}]}') + request = json.loads(r'{"type":"edge instantiable","name":"sunt occaecat eu aliquip dolor","description":"dolor elit","codeUrl":"https://cG.onvj8"}') parameter_list = [{"changedUrl": "test_string", }, {}, ] for parameters in parameter_list: - response_200_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_200_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.update_device(url=url, body=request, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_200_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.update_device(url=url_variant, body=request, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'{"type":"device","owner":"http://wrvuppqewWdH.omhcAwZEk9qD7opUiXkFBrRItQoqFDF7XVlUNBNhMuyCMYhjfpg7qrt-Fj5hqnNkDvd8tzmY60V61j","url":"http://uFaodEpKyQkGvFI.gotilvYR.udrlbOB-hlPogvYKzKk","description":"fugiat eiusmod","name":"aute consequat veniam","services":[],"experiment":"http://RdmTyMiQYSUxtCuahvebSpQ.enR73CD5qG","connected":false}') + response_200_dict = json.loads(r'{"url":"https://rKemGKMlhNcfBAeYBDdlNW.ieM9N.ZnfxWisMIs34TWLplCB-AYjE6sICZDnfHOU1at","type":"group","name":"proident in anim aute veniam","owner":"https://HeFvjzydnbDafLWsZ.ixrN4oC-Om8TxgI0e.UVQRAyQNqrmskvLXxQSwdSjMZxmIrHvBPiS307XfTFjCY4..V.NUWa","devices":[{"url":"http://EERXg.nkpheF89-oujBOjoCcKDypbFgx0i"},{"url":"http://fdUnFNwDkNezzoCuEPhlYWOEvUdg.rhvBAUIwDQHkbofP-+BcBFqXBdlYPoNVsh,fx4"},{"url":"https://rY.hhvlVeTbT7OW,x1xiuZKPifCtJtDRbd4VNKiO3vRRWzabEtMoO"},{"url":"https://JXERGYXtciXGYWUmSxLRqwnekbIe.pdrQmp3KnpoCaCEYnMowadp7L9pb6m3slUHiiyUGjJY-aE5oeJyEY1m3V3"}],"description":"sint sit"}') aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.update_device(url=full_url, body=request, **parameters) @@ -4502,21 +4502,21 @@ async def test_instantiate_device(aioresponses: aioresponses): parameter_list = [{"changedUrl": "test_string", }, {}, ] for parameters in parameter_list: - response_201_dict = json.loads(r'{"instance":{"announcedAvailability":[{"start":"1955-04-07T01:22:58.0Z","end":"1995-07-10T11:59:14.0Z"},{"end":"2006-05-22T14:58:01.0Z","start":"1956-06-29T18:16:35.0Z"},{"end":"2013-11-28T07:03:49.0Z"},{"end":"2015-04-21T18:19:04.0Z","start":"1975-07-14T08:16:38.0Z"}],"url":"http://uqyLriKDNyKa.qeZcaJtVX9mfvD76xUF+W4nYYFiXhN--1QmKZdxJnnq","services":[],"type":"device","connected":true,"name":"in","owner":"http://XtPxmagFFBylFzvNnkgMTYi.yvmlIqZeAORZPbJktCdGBIj2aFx5zB","description":"nostrud Lorem commodo Excepteur","experiment":"http://ziGqQoyUsaiCVXWUsGq.vgYEjjfQYlaoNU0.TNshwmZX97ESZapPxeXRR6oyHetq"},"deviceToken":"irure eu"}') + response_201_dict = json.loads(r'{"instance":{"url":"https://CqYON.xmnuGYeEv6A,Y1Xd","type":"device","name":"fugiat labore Lorem nostrud","owner":"http://qXJqGDlmidYcvasqfsCCA.eljeTAmkIX2L2AzMelvRPbXU2YfsxCWZ,n7TfiEJDoV5cMeYV97+9gjfC","connected":false,"description":"sint","announcedAvailability":[{"end":"1963-07-05T07:30:35.0Z"},{"end":"1944-01-03T21:37:04.0Z","start":"2008-03-20T19:50:34.0Z"},{"end":"1949-11-16T11:53:26.0Z","start":"1959-09-24T01:59:32.0Z"}],"experiment":"https://hSjlrWjjdOTifzKcyxsUt.wnzgp6pqUPFhd9zE6zHT1PW-LHrPsEIuTVAlx-pza8oCKVda","services":[{"serviceType":"http://UlpUhSJkIblJFycFQKfNQ.uytgIvHKxi7VK3RVSvVkGu.8MgKITDwWuLEVTBJkV,4qA7tV6OGerfaUrZw4wcN,o","serviceId":"mollit veniam proident occaecat","serviceDirection":"prosumer"},{"serviceId":"quis ad commodo nostrud dolor","serviceDirection":"prosumer","serviceType":"http://MOaPANKswMkLZU.gayowe-SJNQJJxwE91c"},{"serviceDirection":"prosumer","serviceId":"irure dolor exercitation pariatur consectetur"},{"serviceType":"http://AgJRgzRBfjnukmtIBBFrlUlDU.galiTbGmNW-xMV4pZWb8DrVytQtTCB1cSVCL4n2l-a3OPVNlMJjDnRSf2tBLukDnnhMUGt7M9G","serviceId":"sunt tempor sed ut nulla"},{"serviceDirection":"prosumer","serviceType":"https://KyJelqOfDmRxnJPzuJBtlBq.hobIWQQ1fv9+"}]},"deviceToken":"cillum ullamco"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.instantiate_device(url=url, **parameters) assert normalize_result(resp) == normalize_result(response_201_dict) for parameters in parameter_list: - response_201_dict = json.loads(r'{"instance":{"announcedAvailability":[{"start":"1955-04-07T01:22:58.0Z","end":"1995-07-10T11:59:14.0Z"},{"end":"2006-05-22T14:58:01.0Z","start":"1956-06-29T18:16:35.0Z"},{"end":"2013-11-28T07:03:49.0Z"},{"end":"2015-04-21T18:19:04.0Z","start":"1975-07-14T08:16:38.0Z"}],"url":"http://uqyLriKDNyKa.qeZcaJtVX9mfvD76xUF+W4nYYFiXhN--1QmKZdxJnnq","services":[],"type":"device","connected":true,"name":"in","owner":"http://XtPxmagFFBylFzvNnkgMTYi.yvmlIqZeAORZPbJktCdGBIj2aFx5zB","description":"nostrud Lorem commodo Excepteur","experiment":"http://ziGqQoyUsaiCVXWUsGq.vgYEjjfQYlaoNU0.TNshwmZX97ESZapPxeXRR6oyHetq"},"deviceToken":"irure eu"}') + response_201_dict = json.loads(r'{"instance":{"url":"https://CqYON.xmnuGYeEv6A,Y1Xd","type":"device","name":"fugiat labore Lorem nostrud","owner":"http://qXJqGDlmidYcvasqfsCCA.eljeTAmkIX2L2AzMelvRPbXU2YfsxCWZ,n7TfiEJDoV5cMeYV97+9gjfC","connected":false,"description":"sint","announcedAvailability":[{"end":"1963-07-05T07:30:35.0Z"},{"end":"1944-01-03T21:37:04.0Z","start":"2008-03-20T19:50:34.0Z"},{"end":"1949-11-16T11:53:26.0Z","start":"1959-09-24T01:59:32.0Z"}],"experiment":"https://hSjlrWjjdOTifzKcyxsUt.wnzgp6pqUPFhd9zE6zHT1PW-LHrPsEIuTVAlx-pza8oCKVda","services":[{"serviceType":"http://UlpUhSJkIblJFycFQKfNQ.uytgIvHKxi7VK3RVSvVkGu.8MgKITDwWuLEVTBJkV,4qA7tV6OGerfaUrZw4wcN,o","serviceId":"mollit veniam proident occaecat","serviceDirection":"prosumer"},{"serviceId":"quis ad commodo nostrud dolor","serviceDirection":"prosumer","serviceType":"http://MOaPANKswMkLZU.gayowe-SJNQJJxwE91c"},{"serviceDirection":"prosumer","serviceId":"irure dolor exercitation pariatur consectetur"},{"serviceType":"http://AgJRgzRBfjnukmtIBBFrlUlDU.galiTbGmNW-xMV4pZWb8DrVytQtTCB1cSVCL4n2l-a3OPVNlMJjDnRSf2tBLukDnnhMUGt7M9G","serviceId":"sunt tempor sed ut nulla"},{"serviceDirection":"prosumer","serviceType":"https://KyJelqOfDmRxnJPzuJBtlBq.hobIWQQ1fv9+"}]},"deviceToken":"cillum ullamco"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.instantiate_device(url=url_variant, **parameters) assert normalize_result(resp) == normalize_result(response_201_dict) for parameters in parameter_list: - response_201_dict = json.loads(r'{"instance":{"announcedAvailability":[{"start":"1955-04-07T01:22:58.0Z","end":"1995-07-10T11:59:14.0Z"},{"end":"2006-05-22T14:58:01.0Z","start":"1956-06-29T18:16:35.0Z"},{"end":"2013-11-28T07:03:49.0Z"},{"end":"2015-04-21T18:19:04.0Z","start":"1975-07-14T08:16:38.0Z"}],"url":"http://uqyLriKDNyKa.qeZcaJtVX9mfvD76xUF+W4nYYFiXhN--1QmKZdxJnnq","services":[],"type":"device","connected":true,"name":"in","owner":"http://XtPxmagFFBylFzvNnkgMTYi.yvmlIqZeAORZPbJktCdGBIj2aFx5zB","description":"nostrud Lorem commodo Excepteur","experiment":"http://ziGqQoyUsaiCVXWUsGq.vgYEjjfQYlaoNU0.TNshwmZX97ESZapPxeXRR6oyHetq"},"deviceToken":"irure eu"}') + response_201_dict = json.loads(r'{"instance":{"url":"https://CqYON.xmnuGYeEv6A,Y1Xd","type":"device","name":"fugiat labore Lorem nostrud","owner":"http://qXJqGDlmidYcvasqfsCCA.eljeTAmkIX2L2AzMelvRPbXU2YfsxCWZ,n7TfiEJDoV5cMeYV97+9gjfC","connected":false,"description":"sint","announcedAvailability":[{"end":"1963-07-05T07:30:35.0Z"},{"end":"1944-01-03T21:37:04.0Z","start":"2008-03-20T19:50:34.0Z"},{"end":"1949-11-16T11:53:26.0Z","start":"1959-09-24T01:59:32.0Z"}],"experiment":"https://hSjlrWjjdOTifzKcyxsUt.wnzgp6pqUPFhd9zE6zHT1PW-LHrPsEIuTVAlx-pza8oCKVda","services":[{"serviceType":"http://UlpUhSJkIblJFycFQKfNQ.uytgIvHKxi7VK3RVSvVkGu.8MgKITDwWuLEVTBJkV,4qA7tV6OGerfaUrZw4wcN,o","serviceId":"mollit veniam proident occaecat","serviceDirection":"prosumer"},{"serviceId":"quis ad commodo nostrud dolor","serviceDirection":"prosumer","serviceType":"http://MOaPANKswMkLZU.gayowe-SJNQJJxwE91c"},{"serviceDirection":"prosumer","serviceId":"irure dolor exercitation pariatur consectetur"},{"serviceType":"http://AgJRgzRBfjnukmtIBBFrlUlDU.galiTbGmNW-xMV4pZWb8DrVytQtTCB1cSVCL4n2l-a3OPVNlMJjDnRSf2tBLukDnnhMUGt7M9G","serviceId":"sunt tempor sed ut nulla"},{"serviceDirection":"prosumer","serviceType":"https://KyJelqOfDmRxnJPzuJBtlBq.hobIWQQ1fv9+"}]},"deviceToken":"cillum ullamco"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.instantiate_device(url=full_url, **parameters) @@ -4619,7 +4619,7 @@ async def test_add_availability_rules(aioresponses: aioresponses): url_variant = r'devices/c799cc2e-cdc5-4143-973a-6f56a5afa82c/availability' full_url = BASE_URL+r'/devices/c799cc2e-cdc5-4143-973a-6f56a5afa82c/availability' - request = json.loads(r'[{"start":"1976-10-07T22:53:32.0Z","end":"2021-01-23T10:58:58.0Z","available":true,"repeat":{"until":"1999-07-02T02:45:39.0Z"}},{"end":"1987-01-05T01:08:15.0Z"}]') + request = json.loads(r'[{"start":"1976-10-07T22:53:32.0Z","end":"2021-01-23T10:58:58.0Z","available":true,"repeat":{"frequency":"DAILY","count":-28462768,"until":"2022-08-07T23:17:41.0Z"}},{"repeat":{"frequency":"HOURLY"},"start":"1943-11-02T13:33:50.0Z","available":true}]') parameter_list = [{}, ] @@ -4861,7 +4861,7 @@ async def test_send_signaling_message(aioresponses: aioresponses): url_variant = r'devices/c799cc2e-cdc5-4143-973a-6f56a5afa82c/signaling' full_url = BASE_URL+r'/devices/c799cc2e-cdc5-4143-973a-6f56a5afa82c/signaling' - request = json.loads(r'{"messageType":"command","command":"createPeerconnection","connectionType":"websocket","connectionUrl":"http://mSxcAxcNBEEObpLmSlWMbhgcDFFq.phuibR+NAH9qR2hG,VoGNZCgZKXd5f-JF","services":[{"serviceType":"https://WN.yyqil0X0kH-nSbucxHwUKTp6riWuOEsxSyNTZz","serviceId":"ad reprehenderit","remoteServiceId":"laborum velit"},{"serviceType":"https://GaxqG.fcVGX0FK","serviceId":"exercitation","remoteServiceId":"dolor magna in proident"}],"tiebreaker":true,"config":{}}') + request = json.loads(r'{"messageType":"command","command":"createPeerconnection","connectionType":"local","connectionUrl":"http://mSxcAxcNBEEObpLmSlWMbhgcDFFq.phuibR+NAH9qR2hG,VoGNZCgZKXd5f-JF","services":[{"serviceType":"https://WN.yyqil0X0kH-nSbucxHwUKTp6riWuOEsxSyNTZz","serviceId":"ad reprehenderit","remoteServiceId":"laborum velit"},{"serviceType":"https://GaxqG.fcVGX0FK","serviceId":"exercitation","remoteServiceId":"dolor magna in proident"}],"tiebreaker":true,"config":{}}') parameter_list = [{"peerconnection_url": "test_string", }, ] @@ -4980,28 +4980,28 @@ async def test_list_peerconnections(aioresponses: aioresponses): parameter_list = [{}, ] for parameters in parameter_list: - response_200_dict = json.loads(r'[{"devices":[{"url":"https://AcAm.lbXLj6e"},{"url":"http://XrTgiHePnXvRPczPBULvYtI.wsavVsuGOEjKj7O3CmZC3P2wKB4,hn4VXd6cXxcgqpSF9gDwinLCTPN0xjFVloE.mcO9"}],"url":"https://HdGqlUwYyIraClLraHacgbNvWINA.clJ3KvdUzu2GNj4hKj,RdgY6seg"},{"devices":[{"url":"https://iIRIvlwbF.obmg.EeycdcbdoSy62ARR1HP7BQpX"},{"url":"https://XnJbyygWStGohyNKERsjdkm.urE4I2GeltAe-"}]}]') + response_200_dict = json.loads(r'[{"url":"http://ZdTGPafFTFdOrlsRXKyoRQQ.ykdvKuq2vr32FegxRPOh7SbwHe","type":"local","devices":[{"url":"http://MhMUVnnIiUwsDRP.dudoT3yvSYQE1d27VYw9SbeCwsMFSzANMjBX0khQv6NcHEvF3MocDmv3lCMsENLY2rOFl.L"},{"url":"http://bFEJIqVUszBtNaxcvsWHfk.sirLBbny3VnBXE15oLcPZcQCi+"}],"status":"failed"},{"url":"http://LSFtmxDGOckRkViTFUiPPfXHnDvVkTLb.gwgkhwi9UO6GjEY0YNIKH18qLk","type":"local","devices":[{"url":"https://iqKdIcgcdciNq.pssaJMJuCgqPDfq4OM"},{"url":"http://TAKplEZJJnnAqUfuWTtulgjbHWC.khszpn3K.Y"}],"status":"connecting"},{"url":"http://fXVcBpEXDHmsMsDObV.hfACXLVvqZIqVxD.P8LQJdNN217pP,GAcwamid57SsHQwb","type":"webrtc","devices":[{"url":"http://upvFODDKBjYeysg.sbEHDzuy6CyZ-WogHoZ.MMvsmVR4RnrN6"},{"url":"http://JVwylE.nwmvBU4d6-PXj6OVok"}],"status":"connected"},{"url":"https://rMqZjtqZAenxRreKbLZLvmhHtE.eifsXQVOsinjFLRzFcohzkpDf1fMPRcLTYJA3S9Udo3NZUTYErE,1ovL","type":"local","devices":[{"url":"https://D.ldvaox8BCk8omTCJrY"},{"url":"http://dfUr.ilZEln+qEHrE4jQIxURnGf7yU-xVT6GfYt6NCgSZxHT0zxLPX-w"}],"status":"failed"}]') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.list_peerconnections(**parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'[{"devices":[{"url":"https://AcAm.lbXLj6e"},{"url":"http://XrTgiHePnXvRPczPBULvYtI.wsavVsuGOEjKj7O3CmZC3P2wKB4,hn4VXd6cXxcgqpSF9gDwinLCTPN0xjFVloE.mcO9"}],"url":"https://HdGqlUwYyIraClLraHacgbNvWINA.clJ3KvdUzu2GNj4hKj,RdgY6seg"},{"devices":[{"url":"https://iIRIvlwbF.obmg.EeycdcbdoSy62ARR1HP7BQpX"},{"url":"https://XnJbyygWStGohyNKERsjdkm.urE4I2GeltAe-"}]}]') + response_200_dict = json.loads(r'[{"url":"http://ZdTGPafFTFdOrlsRXKyoRQQ.ykdvKuq2vr32FegxRPOh7SbwHe","type":"local","devices":[{"url":"http://MhMUVnnIiUwsDRP.dudoT3yvSYQE1d27VYw9SbeCwsMFSzANMjBX0khQv6NcHEvF3MocDmv3lCMsENLY2rOFl.L"},{"url":"http://bFEJIqVUszBtNaxcvsWHfk.sirLBbny3VnBXE15oLcPZcQCi+"}],"status":"failed"},{"url":"http://LSFtmxDGOckRkViTFUiPPfXHnDvVkTLb.gwgkhwi9UO6GjEY0YNIKH18qLk","type":"local","devices":[{"url":"https://iqKdIcgcdciNq.pssaJMJuCgqPDfq4OM"},{"url":"http://TAKplEZJJnnAqUfuWTtulgjbHWC.khszpn3K.Y"}],"status":"connecting"},{"url":"http://fXVcBpEXDHmsMsDObV.hfACXLVvqZIqVxD.P8LQJdNN217pP,GAcwamid57SsHQwb","type":"webrtc","devices":[{"url":"http://upvFODDKBjYeysg.sbEHDzuy6CyZ-WogHoZ.MMvsmVR4RnrN6"},{"url":"http://JVwylE.nwmvBU4d6-PXj6OVok"}],"status":"connected"},{"url":"https://rMqZjtqZAenxRreKbLZLvmhHtE.eifsXQVOsinjFLRzFcohzkpDf1fMPRcLTYJA3S9Udo3NZUTYErE,1ovL","type":"local","devices":[{"url":"https://D.ldvaox8BCk8omTCJrY"},{"url":"http://dfUr.ilZEln+qEHrE4jQIxURnGf7yU-xVT6GfYt6NCgSZxHT0zxLPX-w"}],"status":"failed"}]') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.list_peerconnections(url=url, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'[{"devices":[{"url":"https://AcAm.lbXLj6e"},{"url":"http://XrTgiHePnXvRPczPBULvYtI.wsavVsuGOEjKj7O3CmZC3P2wKB4,hn4VXd6cXxcgqpSF9gDwinLCTPN0xjFVloE.mcO9"}],"url":"https://HdGqlUwYyIraClLraHacgbNvWINA.clJ3KvdUzu2GNj4hKj,RdgY6seg"},{"devices":[{"url":"https://iIRIvlwbF.obmg.EeycdcbdoSy62ARR1HP7BQpX"},{"url":"https://XnJbyygWStGohyNKERsjdkm.urE4I2GeltAe-"}]}]') + response_200_dict = json.loads(r'[{"url":"http://ZdTGPafFTFdOrlsRXKyoRQQ.ykdvKuq2vr32FegxRPOh7SbwHe","type":"local","devices":[{"url":"http://MhMUVnnIiUwsDRP.dudoT3yvSYQE1d27VYw9SbeCwsMFSzANMjBX0khQv6NcHEvF3MocDmv3lCMsENLY2rOFl.L"},{"url":"http://bFEJIqVUszBtNaxcvsWHfk.sirLBbny3VnBXE15oLcPZcQCi+"}],"status":"failed"},{"url":"http://LSFtmxDGOckRkViTFUiPPfXHnDvVkTLb.gwgkhwi9UO6GjEY0YNIKH18qLk","type":"local","devices":[{"url":"https://iqKdIcgcdciNq.pssaJMJuCgqPDfq4OM"},{"url":"http://TAKplEZJJnnAqUfuWTtulgjbHWC.khszpn3K.Y"}],"status":"connecting"},{"url":"http://fXVcBpEXDHmsMsDObV.hfACXLVvqZIqVxD.P8LQJdNN217pP,GAcwamid57SsHQwb","type":"webrtc","devices":[{"url":"http://upvFODDKBjYeysg.sbEHDzuy6CyZ-WogHoZ.MMvsmVR4RnrN6"},{"url":"http://JVwylE.nwmvBU4d6-PXj6OVok"}],"status":"connected"},{"url":"https://rMqZjtqZAenxRreKbLZLvmhHtE.eifsXQVOsinjFLRzFcohzkpDf1fMPRcLTYJA3S9Udo3NZUTYErE,1ovL","type":"local","devices":[{"url":"https://D.ldvaox8BCk8omTCJrY"},{"url":"http://dfUr.ilZEln+qEHrE4jQIxURnGf7yU-xVT6GfYt6NCgSZxHT0zxLPX-w"}],"status":"failed"}]') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.list_peerconnections(url=url_variant, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'[{"devices":[{"url":"https://AcAm.lbXLj6e"},{"url":"http://XrTgiHePnXvRPczPBULvYtI.wsavVsuGOEjKj7O3CmZC3P2wKB4,hn4VXd6cXxcgqpSF9gDwinLCTPN0xjFVloE.mcO9"}],"url":"https://HdGqlUwYyIraClLraHacgbNvWINA.clJ3KvdUzu2GNj4hKj,RdgY6seg"},{"devices":[{"url":"https://iIRIvlwbF.obmg.EeycdcbdoSy62ARR1HP7BQpX"},{"url":"https://XnJbyygWStGohyNKERsjdkm.urE4I2GeltAe-"}]}]') + response_200_dict = json.loads(r'[{"url":"http://ZdTGPafFTFdOrlsRXKyoRQQ.ykdvKuq2vr32FegxRPOh7SbwHe","type":"local","devices":[{"url":"http://MhMUVnnIiUwsDRP.dudoT3yvSYQE1d27VYw9SbeCwsMFSzANMjBX0khQv6NcHEvF3MocDmv3lCMsENLY2rOFl.L"},{"url":"http://bFEJIqVUszBtNaxcvsWHfk.sirLBbny3VnBXE15oLcPZcQCi+"}],"status":"failed"},{"url":"http://LSFtmxDGOckRkViTFUiPPfXHnDvVkTLb.gwgkhwi9UO6GjEY0YNIKH18qLk","type":"local","devices":[{"url":"https://iqKdIcgcdciNq.pssaJMJuCgqPDfq4OM"},{"url":"http://TAKplEZJJnnAqUfuWTtulgjbHWC.khszpn3K.Y"}],"status":"connecting"},{"url":"http://fXVcBpEXDHmsMsDObV.hfACXLVvqZIqVxD.P8LQJdNN217pP,GAcwamid57SsHQwb","type":"webrtc","devices":[{"url":"http://upvFODDKBjYeysg.sbEHDzuy6CyZ-WogHoZ.MMvsmVR4RnrN6"},{"url":"http://JVwylE.nwmvBU4d6-PXj6OVok"}],"status":"connected"},{"url":"https://rMqZjtqZAenxRreKbLZLvmhHtE.eifsXQVOsinjFLRzFcohzkpDf1fMPRcLTYJA3S9Udo3NZUTYErE,1ovL","type":"local","devices":[{"url":"https://D.ldvaox8BCk8omTCJrY"},{"url":"http://dfUr.ilZEln+qEHrE4jQIxURnGf7yU-xVT6GfYt6NCgSZxHT0zxLPX-w"}],"status":"failed"}]') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.list_peerconnections(url=full_url, **parameters) @@ -5134,61 +5134,61 @@ async def test_create_peerconnection(aioresponses: aioresponses): url_variant = r'peerconnections' full_url = BASE_URL+r'/peerconnections' - request = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + request = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') parameter_list = [{"closedUrl": "test_string", "statusChangedUrl": "test_string", }, {"statusChangedUrl": "test_string", }, {"closedUrl": "test_string", }, {}, ] for parameters in parameter_list: - response_201_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_201_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.create_peerconnection(body=request, **parameters) assert normalize_result(resp) == normalize_result(response_201_dict) for parameters in parameter_list: - response_201_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_201_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.create_peerconnection(url=url, body=request, **parameters) assert normalize_result(resp) == normalize_result(response_201_dict) for parameters in parameter_list: - response_201_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_201_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.create_peerconnection(url=url_variant, body=request, **parameters) assert normalize_result(resp) == normalize_result(response_201_dict) for parameters in parameter_list: - response_201_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_201_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201, payload=response_201_dict) async with APIClient(BASE_URL) as client: resp = await client.create_peerconnection(url=full_url, body=request, **parameters) assert normalize_result(resp) == normalize_result(response_201_dict) for parameters in parameter_list: - response_202_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_202_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=202, payload=response_202_dict) async with APIClient(BASE_URL) as client: resp = await client.create_peerconnection(body=request, **parameters) assert normalize_result(resp) == normalize_result(response_202_dict) for parameters in parameter_list: - response_202_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_202_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=202, payload=response_202_dict) async with APIClient(BASE_URL) as client: resp = await client.create_peerconnection(url=url, body=request, **parameters) assert normalize_result(resp) == normalize_result(response_202_dict) for parameters in parameter_list: - response_202_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_202_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=202, payload=response_202_dict) async with APIClient(BASE_URL) as client: resp = await client.create_peerconnection(url=url_variant, body=request, **parameters) assert normalize_result(resp) == normalize_result(response_202_dict) for parameters in parameter_list: - response_202_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_202_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.post(re.compile(re.escape(full_url)+r'(\?.*)?'), status=202, payload=response_202_dict) async with APIClient(BASE_URL) as client: resp = await client.create_peerconnection(url=full_url, body=request, **parameters) @@ -5324,21 +5324,21 @@ async def test_get_peerconnection(aioresponses: aioresponses): parameter_list = [{}, ] for parameters in parameter_list: - response_200_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_200_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.get_peerconnection(url=url, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_200_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.get_peerconnection(url=url_variant, **parameters) assert normalize_result(resp) == normalize_result(response_200_dict) for parameters in parameter_list: - response_200_dict = json.loads(r'{"devices":[{"config":{"services":[{"remoteServiceId":"aliquip cillum sit laboris proident","serviceType":"http://KQNKmkiBeAKZTYtYeKBfWScV.lrytkFxV,ZrP-XBrNY-Pt"},{"remoteServiceId":"non aliqua proident","serviceType":"https://WnrvOdiQDOMpdYMcTq.noO+WfcTGn-SJlF,gLZ.+0sd4lfOBqeRcm0VW3vdF-s5","serviceId":"occaecat"},{"serviceType":"http://ZoSEaDhJkgXvaseY.myrzUuSpBSXiaGe4n-+KHudVEZQfvK3O+nRIwYJTSE5Ny,L","serviceId":"laboris"},{"serviceType":"https://GkopJXScAvTsPblHOnULiGlmEmOkeEn.uwbJBdQI"}]}}],"status":"failed","url":"https://bMJFHTrmqHvixazrXAYqbQYHMSCMKO.yjkNKx6ocxMqy"}') + response_200_dict = json.loads(r'{"url":"https://DELkhyRFPtjZoXBJnD.mpcH-J-JNY1XZPh","type":"webrtc","devices":[{"url":"http://ZjhlonrKlRrZfkk.cliFiylu2KXtjdx9AydImIgMsoHaqpuiwNWj3uTBNYtyoe","config":{"services":[{"serviceType":"https://SWNzRYsADEeZRcyrFQOtuscS.hiMmf5TYqhwWOKUVSmIihYgJxiBZNtkHAhW","serviceId":"deserunt nisi est","remoteServiceId":"in veniam fugiat minim commodo"},{"serviceType":"http://sLogGylMTrxCdLCTjU.oyeyhc-FDU+4wS6XsRVXXtooW8F-DWTPS","serviceId":"Duis","remoteServiceId":"irure consequat ex"},{"serviceType":"http://wbLPLVffzYINTKXmbvyjMAVYH.ujvGmBNAwITuJI89n.iLhmgn.8146VOut-xP75Idys5rN00pHkXEDlz","serviceId":"sunt quis minim aliqua veniam","remoteServiceId":"ipsum fugiat laborum"},{"serviceType":"https://BkfmvWkW.wadmo2WfhYb.IKKeUSq9lrY","serviceId":"Duis magna","remoteServiceId":"consequat ea"},{"serviceType":"https://tBrMngaVgCtVgsi.anMa0BCd.Qisg16arV","serviceId":"eu est culpa ullamco veniam","remoteServiceId":"in ut laborum anim esse"}]}},{"url":"http://iDPxrWlVcZpRStKCKyhCkpdQXu.xxvqtfx.DmAlHgtPMRok-pXizJJ3izr6w7Dk8E.dwuqUKIav2WVdmfv8,L,Cta4C1M2HAs","config":{"services":[{"serviceType":"https://XyGLXYXytmmyqWC.azti68D6mjzmwdOhFZg6XVC9BmswoCJtC-bsVCRfK4SdL8h+.wsBgobiqGZSyWyDitY3CeWP","serviceId":"dolore qui aliqua","remoteServiceId":"dolore incididunt sit Excepteur elit"},{"serviceType":"http://OF.hhvXtULjAIq2crOh-g.FntOP8iXLGUhfWCxnkRxPaWkB","serviceId":"ut","remoteServiceId":"occaecat nisi consequat"},{"serviceType":"https://PknLXTVMCtlNoGJBAfcadpdhuGu.qsaU7Y8bqud-Ly2XyFKd9xbJFkNOdkYTCgSwjta8aiQl7OGseQAwxqcLU.1iGmJW","serviceId":"eu","remoteServiceId":"ut velit consequat Ut"}]}}],"status":"closed"}') aioresponses.get(re.compile(re.escape(full_url)+r'(\?.*)?'), status=200, payload=response_200_dict) async with APIClient(BASE_URL) as client: resp = await client.get_peerconnection(url=full_url, **parameters) @@ -5549,6 +5549,122 @@ async def test_delete_peerconnection(aioresponses: aioresponses): resp = await client.delete_peerconnection(url=full_url, **parameters) +@pytest.mark.asyncio +async def test_patch_peerconnection_device_status(aioresponses: aioresponses): + url = r'/peerconnections/c799cc2e-cdc5-4143-973a-6f56a5afa82c/device_status' + url_variant = r'peerconnections/c799cc2e-cdc5-4143-973a-6f56a5afa82c/device_status' + full_url = BASE_URL+r'/peerconnections/c799cc2e-cdc5-4143-973a-6f56a5afa82c/device_status' + + request = json.loads(r'{"status":"closed"}') + + parameter_list = [{"device_url": "test_string", }, ] + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201) + async with APIClient(BASE_URL) as client: + resp = await client.patch_peerconnection_device_status(url=url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201) + async with APIClient(BASE_URL) as client: + resp = await client.patch_peerconnection_device_status(url=url_variant, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=201) + async with APIClient(BASE_URL) as client: + resp = await client.patch_peerconnection_device_status(url=full_url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=400) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=400) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url_variant, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=400) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=full_url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=401) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=401) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url_variant, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=401) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=full_url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=403) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=403) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url_variant, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=403) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=full_url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=404) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=404) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url_variant, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=404) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=full_url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=500) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=500) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=url_variant, body=request, **parameters) + + for parameters in parameter_list: + aioresponses.patch(re.compile(re.escape(full_url)+r'(\?.*)?'), status=500) + async with APIClient(BASE_URL) as client: + with pytest.raises(Exception): + resp = await client.patch_peerconnection_device_status(url=full_url, body=request, **parameters) + + @pytest.mark.asyncio async def test_list_experiments(aioresponses: aioresponses): url = r'/experiments' diff --git a/clients/soa/.vscode/settings.json b/clients/soa/.vscode/settings.json index 25e84362..63a4dde2 100644 --- a/clients/soa/.vscode/settings.json +++ b/clients/soa/.vscode/settings.json @@ -1,38 +1,16 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, - "./clients/soa_services/.vscode": true, "./clients/soa_services/electricalConnection/.vscode": true, "./clients/soa_services/file/.vscode": true, "./clients/soa_services/message/.vscode": true, + "./clients/soa_services/.vscode": true, "./clients/soa_services/webcam/.vscode": true, //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa/js/.vscode/settings.json b/clients/soa/js/.vscode/settings.json index f90817be..6c65abed 100644 --- a/clients/soa/js/.vscode/settings.json +++ b/clients/soa/js/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa/python/.vscode/settings.json b/clients/soa/python/.vscode/settings.json index 2aadde0b..11925076 100644 --- a/clients/soa/python/.vscode/settings.json +++ b/clients/soa/python/.vscode/settings.json @@ -16,33 +16,12 @@ ], "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/.vscode/settings.json b/clients/soa_services/.vscode/settings.json index 5046f1b8..e4a9ad2d 100644 --- a/clients/soa_services/.vscode/settings.json +++ b/clients/soa_services/.vscode/settings.json @@ -1,17 +1,6 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, "electricalConnection/.vscode": true, "file/.vscode": true, "message/.vscode": true, @@ -20,18 +9,7 @@ }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/electricalConnection/.vscode/settings.json b/clients/soa_services/electricalConnection/.vscode/settings.json index f90817be..65755078 100644 --- a/clients/soa_services/electricalConnection/.vscode/settings.json +++ b/clients/soa_services/electricalConnection/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/electricalConnection/js/.vscode/settings.json b/clients/soa_services/electricalConnection/js/.vscode/settings.json index f90817be..6c65abed 100644 --- a/clients/soa_services/electricalConnection/js/.vscode/settings.json +++ b/clients/soa_services/electricalConnection/js/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/electricalConnection/python/.vscode/settings.json b/clients/soa_services/electricalConnection/python/.vscode/settings.json index 8f7703e3..8f646a93 100644 --- a/clients/soa_services/electricalConnection/python/.vscode/settings.json +++ b/clients/soa_services/electricalConnection/python/.vscode/settings.json @@ -16,33 +16,12 @@ ], "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/clients/soa_services/file/.vscode/settings.json b/clients/soa_services/file/.vscode/settings.json index f90817be..65755078 100644 --- a/clients/soa_services/file/.vscode/settings.json +++ b/clients/soa_services/file/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/file/js/.vscode/settings.json b/clients/soa_services/file/js/.vscode/settings.json index f90817be..6c65abed 100644 --- a/clients/soa_services/file/js/.vscode/settings.json +++ b/clients/soa_services/file/js/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/file/python/.vscode/settings.json b/clients/soa_services/file/python/.vscode/settings.json index 8f7703e3..8f646a93 100644 --- a/clients/soa_services/file/python/.vscode/settings.json +++ b/clients/soa_services/file/python/.vscode/settings.json @@ -16,33 +16,12 @@ ], "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/clients/soa_services/message/.vscode/settings.json b/clients/soa_services/message/.vscode/settings.json index f90817be..65755078 100644 --- a/clients/soa_services/message/.vscode/settings.json +++ b/clients/soa_services/message/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/message/js/.vscode/settings.json b/clients/soa_services/message/js/.vscode/settings.json index f90817be..6c65abed 100644 --- a/clients/soa_services/message/js/.vscode/settings.json +++ b/clients/soa_services/message/js/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/message/python/.vscode/settings.json b/clients/soa_services/message/python/.vscode/settings.json index 8f7703e3..8f646a93 100644 --- a/clients/soa_services/message/python/.vscode/settings.json +++ b/clients/soa_services/message/python/.vscode/settings.json @@ -16,33 +16,12 @@ ], "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/clients/soa_services/webcam/.vscode/settings.json b/clients/soa_services/webcam/.vscode/settings.json index f90817be..65755078 100644 --- a/clients/soa_services/webcam/.vscode/settings.json +++ b/clients/soa_services/webcam/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/webcam/js/.vscode/settings.json b/clients/soa_services/webcam/js/.vscode/settings.json index f90817be..6c65abed 100644 --- a/clients/soa_services/webcam/js/.vscode/settings.json +++ b/clients/soa_services/webcam/js/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/clients/soa_services/webcam/python/.vscode/settings.json b/clients/soa_services/webcam/python/.vscode/settings.json index 8f7703e3..8f646a93 100644 --- a/clients/soa_services/webcam/python/.vscode/settings.json +++ b/clients/soa_services/webcam/python/.vscode/settings.json @@ -16,33 +16,12 @@ ], "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/helper/.vscode/settings.json b/helper/.vscode/settings.json index 194559cc..8982bb16 100644 --- a/helper/.vscode/settings.json +++ b/helper/.vscode/settings.json @@ -1,34 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, "dummy-device/.vscode": true, //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/helper/crosslab-typescript-addon/.vscode/settings.json b/helper/crosslab-typescript-addon/.vscode/settings.json index 1a2d8d88..bbbf33e4 100644 --- a/helper/crosslab-typescript-addon/.vscode/settings.json +++ b/helper/crosslab-typescript-addon/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "[njk]": { diff --git a/helper/dummy-device/.vscode/settings.json b/helper/dummy-device/.vscode/settings.json index f90817be..65755078 100644 --- a/helper/dummy-device/.vscode/settings.json +++ b/helper/dummy-device/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/helper/dummy-device/js/.vscode/settings.json b/helper/dummy-device/js/.vscode/settings.json index f90817be..6c65abed 100644 --- a/helper/dummy-device/js/.vscode/settings.json +++ b/helper/dummy-device/js/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/helper/dummy-device/python/.vscode/settings.json b/helper/dummy-device/python/.vscode/settings.json index 788f0ff4..337964c6 100644 --- a/helper/dummy-device/python/.vscode/settings.json +++ b/helper/dummy-device/python/.vscode/settings.json @@ -11,33 +11,12 @@ "python.analysis.typeCheckingMode": "basic", "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/helper/openapi-codegeneration/.vscode/settings.json b/helper/openapi-codegeneration/.vscode/settings.json index f90817be..6c65abed 100644 --- a/helper/openapi-codegeneration/.vscode/settings.json +++ b/helper/openapi-codegeneration/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/helper/tsdoc-theme/.vscode/settings.json b/helper/tsdoc-theme/.vscode/settings.json index f90817be..6c65abed 100644 --- a/helper/tsdoc-theme/.vscode/settings.json +++ b/helper/tsdoc-theme/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/integration-test/.vscode/settings.json b/integration-test/.vscode/settings.json index f90817be..6c65abed 100644 --- a/integration-test/.vscode/settings.json +++ b/integration-test/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/services/.vscode/settings.json b/services/.vscode/settings.json index f90817be..65755078 100644 --- a/services/.vscode/settings.json +++ b/services/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/services/auth/.vscode/settings.json b/services/auth/.vscode/settings.json index fed86ff6..1c441a1a 100644 --- a/services/auth/.vscode/settings.json +++ b/services/auth/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "mocha.requires": [ diff --git a/services/auth/README.md b/services/auth/README.md index 25edf4de..2adae7c2 100644 --- a/services/auth/README.md +++ b/services/auth/README.md @@ -1,8 +1,8 @@ [//]: # ({{print badges}}) -| | build-spec | lint-spec | build | lint | build-docker | -| --- | --- | --- | --- | --- | --- | -| services/auth | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint-spec.log) | [![build](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build.log) | [![lint](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint.log) | [![build-docker](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-docker.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-docker.log) | +| | build-spec | lint-spec | build | lint | test | build-docker | +| --- | --- | --- | --- | --- | --- | --- | +| services/auth | [![build-spec](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-spec.log) | [![lint-spec](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint-spec.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint-spec.log) | [![build](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build.log) | [![lint](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/lint.log) | [![test](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/test.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/test.log) | [![build-docker](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-docker.badge)](https://ci.goldi-labs.de/crosslab/main/services/auth/dist/build-docker.log) | [//]: # ({{end}}) # Authentication Service @@ -30,6 +30,7 @@ graph LR services/auth:build-spec[build-spec] services/auth:lint[lint] services/auth:lint-spec[lint-spec] + services/auth:test[test] end subgraph services/booking services/booking:build-spec[build-spec] @@ -56,11 +57,12 @@ helper/openapi-codegeneration --> clients/api/js helper/openapi-codegeneration --> helper/crosslab-typescript-addon helper/openapi-codegeneration --> services/auth:build[build] helper/tsdoc-theme --> clients/api/js +services/auth:build[build] --> services/auth:build-docker[build-docker] +services/auth:build[build] --> services/auth:lint[lint] +services/auth:build[build] --> services/auth:test[test] services/auth:build-spec[build-spec] --> clients/api/js services/auth:build-spec[build-spec] --> services/auth:build[build] services/auth:build-spec[build-spec] --> services/auth:lint-spec[lint-spec] -services/auth:build[build] --> services/auth:build-docker[build-docker] -services/auth:build[build] --> services/auth:lint[lint] services/booking --> clients/api/js services/common --> services/auth:build[build] services/device --> clients/api/js diff --git a/services/auth/addShebang.js b/services/auth/addShebang.js new file mode 100644 index 00000000..1bfabec9 --- /dev/null +++ b/services/auth/addShebang.js @@ -0,0 +1,4 @@ +const fs = require("fs") + +const indexJS = fs.readFileSync("./app/index.js") +fs.writeFileSync("./app/index.js", "#!/usr/bin/env node\n" + indexJS) \ No newline at end of file diff --git a/services/auth/package.json b/services/auth/package.json index 7b335d80..9294ed20 100644 --- a/services/auth/package.json +++ b/services/auth/package.json @@ -17,6 +17,7 @@ "build:generate:test": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service:test -o test/generated", "build:generate": "npm-run-all build:generate:*", "build:compile": "tsc --project tsconfig.build.json", + "build:add-shebang": "node addShebang.js", "build": "npm-run-all build:*", "start": "node app/index.js", "dev": "env-cmd -e development npx nodemon src/index.ts", @@ -96,4 +97,4 @@ "winston": "^3.8.1", "ws": "^8.8.0" } -} +} \ No newline at end of file diff --git a/services/auth/scripts/test.sh b/services/auth/scripts/test.sh new file mode 120000 index 00000000..6f4b7cf8 --- /dev/null +++ b/services/auth/scripts/test.sh @@ -0,0 +1 @@ +../../../common/node/scripts/test.sh \ No newline at end of file diff --git a/services/auth/src/index.ts b/services/auth/src/index.ts index dd61e5d7..2451d216 100644 --- a/services/auth/src/index.ts +++ b/services/auth/src/index.ts @@ -1,5 +1,3 @@ -#!/usr/bin/env node - import { config, dataSourceConfig } from './config' import { AppDataSource, initializeDataSource } from './database/dataSource' import { app } from './generated' diff --git a/services/auth/test/operations/auth/get.spec.ts b/services/auth/test/operations/auth/get.spec.ts index 2b245ec9..1401412f 100644 --- a/services/auth/test/operations/auth/get.spec.ts +++ b/services/auth/test/operations/auth/get.spec.ts @@ -99,7 +99,6 @@ export default function (context: Mocha.Context, testData: TestData) { let allowlistedIP: string suite.beforeAll(function () { - this.timeout(0) expiredToken = testData.tokens['GET /auth expired token'].model.token invalidToken = 'invalid' validDeviceToken = testData.tokens['GET /auth valid device token'].model.token diff --git a/services/auth/test/operations/deviceAuthenticationToken/post.spec.ts b/services/auth/test/operations/deviceAuthenticationToken/post.spec.ts index c5efa6d6..683fa4fe 100644 --- a/services/auth/test/operations/deviceAuthenticationToken/post.spec.ts +++ b/services/auth/test/operations/deviceAuthenticationToken/post.spec.ts @@ -15,7 +15,11 @@ export default function (context: Mocha.Context, testData: TestData) { suite.beforeAll(function () { getDeviceStub = sinon.stub(API, 'getDevice') getDeviceStub.resolves({ - owner: testData.users['POST /device_authentication_token user'].response.url, + type: "device", + url: "https://localhost/devices/39db5f84-2ed1-491d-b0e1-f48463a6b748", + name: "Test Device", + owner: testData.users['POST /device_authentication_token user'].response.url!, + }) }) diff --git a/services/booking/.vscode/settings.json b/services/booking/.vscode/settings.json index f90817be..6c65abed 100644 --- a/services/booking/.vscode/settings.json +++ b/services/booking/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/services/common/.vscode/settings.json b/services/common/.vscode/settings.json index f90817be..6c65abed 100644 --- a/services/common/.vscode/settings.json +++ b/services/common/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/services/device/.vscode/settings.json b/services/device/.vscode/settings.json index f90817be..6c65abed 100644 --- a/services/device/.vscode/settings.json +++ b/services/device/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/services/device/scripts/test.sh b/services/device/scripts/test.sh new file mode 120000 index 00000000..6f4b7cf8 --- /dev/null +++ b/services/device/scripts/test.sh @@ -0,0 +1 @@ +../../../common/node/scripts/test.sh \ No newline at end of file diff --git a/services/experiment/.vscode/settings.json b/services/experiment/.vscode/settings.json index f90817be..6c65abed 100644 --- a/services/experiment/.vscode/settings.json +++ b/services/experiment/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/services/experiment/src/database/methods/create.ts b/services/experiment/src/database/methods/create.ts index e4274a40..5ae88b61 100644 --- a/services/experiment/src/database/methods/create.ts +++ b/services/experiment/src/database/methods/create.ts @@ -66,7 +66,6 @@ export function createPeerconnectionModel( peerconnectionUrl: string ): PeerconnectionModel { const peerconnectionModel = peerconnectionRepository.create() - peerconnectionModel.status = "waiting-for-devices" requestHandler.executeSync( writePeerconnectionModel, peerconnectionModel, diff --git a/services/experiment/src/database/model.ts b/services/experiment/src/database/model.ts index 821f1492..577751c8 100644 --- a/services/experiment/src/database/model.ts +++ b/services/experiment/src/database/model.ts @@ -5,6 +5,7 @@ import { DeleteDateColumn, ManyToOne, OneToMany, + PrimaryColumn, } from 'typeorm' @Entity({ name: 'Experiment' }) @@ -72,12 +73,8 @@ export class DeviceModel { @Entity({ name: 'Peerconnection' }) export class PeerconnectionModel { - @PrimaryGeneratedColumn('uuid') - uuid!: string - @Column({ unique: true }) + @PrimaryColumn() url!: string - @Column() - status?: 'waiting-for-devices' | 'connected' | 'failed' | 'closed' @ManyToOne(() => ExperimentModel, (experiment) => experiment.connections) experiment!: ExperimentModel } @@ -87,7 +84,7 @@ export class ServiceConfigurationModel { @PrimaryGeneratedColumn('uuid') uuid!: string @Column() - serviceType?: string + serviceType!: string @Column("simple-json") configuration?: { [k: string]: any @@ -109,7 +106,7 @@ export class ParticipantModel { @Column() role?: string @Column() - serviceId?: string + serviceId!: string @Column("simple-json") config?: { [k: string]: any diff --git a/services/experiment/src/util/api.ts b/services/experiment/src/util/api.ts index 77e45236..ce22c43b 100644 --- a/services/experiment/src/util/api.ts +++ b/services/experiment/src/util/api.ts @@ -190,14 +190,14 @@ export async function startCloudDeviceInstance( experimentUrl: string ) { try { - if (!device.instantiate_url) + if (!device.instantiateUrl) requestHandler.throw( MissingPropertyError, 'Resolved instantiable cloud device does not have an instantiate url', 500 ) // NOTE: error code? await fetch( - device.instantiate_url + + device.instantiateUrl + new URLSearchParams([ ['device_url', deviceUrl], ['token', token], diff --git a/services/experiment/src/util/callbacks.ts b/services/experiment/src/util/callbacks.ts index 974d0a49..38ebfc90 100644 --- a/services/experiment/src/util/callbacks.ts +++ b/services/experiment/src/util/callbacks.ts @@ -170,9 +170,6 @@ async function handlePeerconnectionStatusChangedEventCallback( if (!DeviceServiceTypes.isPeerconnection(peerconnection)) { throw new MalformedBodyError('Property "peerconnection" is malformed', 400) } - if (!peerconnection.url) { - throw new MissingPropertyError('Property "peerconnection" is missing property "url"', 400) - } if (!peerconnectionStatusChangedCallbacks.includes(peerconnection.url)) { return 410 // TODO: find a solution for this problem (race condition) } @@ -192,7 +189,6 @@ async function handlePeerconnectionStatusChangedEventCallback( 500 ) // NOTE: error code - peerconnectionModel.status = peerconnection.status const experimentModel = peerconnectionModel.experiment if (!experimentModel) requestHandler.throw( @@ -200,7 +196,7 @@ async function handlePeerconnectionStatusChangedEventCallback( `Peerconnection model is missing property "experiment"` ) // NOTE: error code - switch (peerconnectionModel.status) { + switch (peerconnection.status) { case 'closed': // TODO: handle status closed break @@ -209,7 +205,8 @@ async function handlePeerconnectionStatusChangedEventCallback( if (!experimentModel.connections) requestHandler.throw( MissingPropertyError, - `Experiment model is missing property "connections"` + `Experiment model is missing property "connections"`, + 400 ) // NOTE: error code // eslint-disable-next-line no-case-declarations @@ -230,8 +227,14 @@ async function handlePeerconnectionStatusChangedEventCallback( case 'failed': // TODO: handle status failed break - case 'waiting-for-devices': - // TODO: handle status waiting-for-devices + case 'new': + // TODO: handle status new + break + case 'connecting': + // TODO: handle status connecting + break + case 'disconnected': + // TODO: handle status disconnected break } return 200 diff --git a/services/experiment/src/util/connectionPlan.ts b/services/experiment/src/util/connectionPlan.ts index 32375df4..3fb35e73 100644 --- a/services/experiment/src/util/connectionPlan.ts +++ b/services/experiment/src/util/connectionPlan.ts @@ -12,7 +12,7 @@ import { experimentUrlFromId, getUrlOrInstanceUrl } from './url' export function buildConnectionPlan( requestHandler: RequestHandler, experiment: ExperimentModel -): DeviceServiceTypes.Peerconnection[] { +): DeviceServiceTypes.Peerconnection<"request">[] { const experimentUrl = requestHandler.executeSync(experimentUrlFromId, experiment.uuid) requestHandler.log('info', `Building connection plan for experiment ${experimentUrl}`) console.log('building connection plan for experiment', experiment.uuid) @@ -48,7 +48,7 @@ export function buildConnectionPlan( const peerconnections: Record< string, - Pick, 'devices'> + DeviceServiceTypes.Peerconnection<"request"> > = {} for (const serviceConfig of sortedDeviceMappedServiceConfigs) { // HOTFIX: for local services: Don't connect local services to each other @@ -59,6 +59,7 @@ export function buildConnectionPlan( const lookupKey = `${serviceConfig.devices[0].url}::${serviceConfig.devices[1].url}` if (!(lookupKey in peerconnections)) { peerconnections[lookupKey] = { + type: "webrtc", devices: [ { url: requestHandler.executeSync( diff --git a/services/federation/.vscode/settings.json b/services/federation/.vscode/settings.json index f90817be..6c65abed 100644 --- a/services/federation/.vscode/settings.json +++ b/services/federation/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/services/gateway/.vscode/settings.json b/services/gateway/.vscode/settings.json index f90817be..6c65abed 100644 --- a/services/gateway/.vscode/settings.json +++ b/services/gateway/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/services/openapi/.vscode/settings.json b/services/openapi/.vscode/settings.json index f90817be..6c65abed 100644 --- a/services/openapi/.vscode/settings.json +++ b/services/openapi/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } diff --git a/services/update/.vscode/settings.json b/services/update/.vscode/settings.json index f90817be..6c65abed 100644 --- a/services/update/.vscode/settings.json +++ b/services/update/.vscode/settings.json @@ -1,33 +1,12 @@ { "files.exclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated }, "files.watcherExclude": { //begin generated - "**/*.egg-info": true, - "**/.mypy_cache": true, - "**/.packages": true, - "**/.pytest_cache": true, - "**/.tox": true, - "**/__pycache__": true, - "**/app": true, - "**/build": true, - "**/dist": true, - "**/lib": true, - "**/node_modules": true, - "**/venv": true, + //end generated } } From 43c3a90c615aa01840959bafe3e5233b3bc008e4 Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Wed, 26 Apr 2023 11:20:49 +0000 Subject: [PATCH 31/33] Fix linting errors --- .vscode/settings.json | 8 +- clients/.vscode/settings.json | 27 ++++++- clients/api/.vscode/settings.json | 24 +++++- clients/api/js/.vscode/settings.json | 24 +++++- clients/api/python/.vscode/settings.json | 24 +++++- clients/soa/.vscode/settings.json | 25 +++++- clients/soa/js/.vscode/settings.json | 24 +++++- clients/soa/python/.vscode/settings.json | 24 +++++- clients/soa_services/.vscode/settings.json | 23 +++++- .../.vscode/settings.json | 24 +++++- .../js/.vscode/settings.json | 24 +++++- .../python/.vscode/settings.json | 24 +++++- .../soa_services/file/.vscode/settings.json | 24 +++++- .../file/js/.vscode/settings.json | 24 +++++- .../file/python/.vscode/settings.json | 24 +++++- .../message/.vscode/settings.json | 24 +++++- .../message/js/.vscode/settings.json | 24 +++++- .../message/python/.vscode/settings.json | 24 +++++- .../soa_services/webcam/.vscode/settings.json | 24 +++++- .../webcam/js/.vscode/settings.json | 24 +++++- .../webcam/python/.vscode/settings.json | 24 +++++- common/node/.eslintrc | 1 + helper/.vscode/settings.json | 23 +++++- .../.vscode/settings.json | 24 +++++- .../typescript/filters/common/stringify.ts | 2 +- .../filters/resolve/resolveSchemas.ts | 2 +- .../typescript/resolve/resolveSchemas.ts | 2 +- .../schema-generation/invalidSchemas.ts | 5 +- .../schema-generation/withoutUnrequired.ts | 2 +- .../typescript/typings/destructure.ts | 2 +- .../typescript/typings/typing.ts | 5 +- helper/dummy-device/.vscode/settings.json | 24 +++++- helper/dummy-device/js/.vscode/settings.json | 24 +++++- .../dummy-device/python/.vscode/settings.json | 24 +++++- .../.vscode/settings.json | 24 +++++- .../python-test-helper/.vscode/settings.json | 1 - helper/tsdoc-theme/.vscode/settings.json | 24 +++++- integration-test/.vscode/settings.json | 24 +++++- services/.vscode/settings.json | 24 +++++- services/auth/.vscode/settings.json | 24 +++++- services/auth/README.md | 6 +- .../deviceAuthenticationToken/post.spec.ts | 79 +++++++++---------- services/booking/.vscode/settings.json | 24 +++++- services/common/.vscode/settings.json | 24 +++++- .../common/src/database/abstractDataSource.ts | 2 +- .../common/src/database/abstractRepository.ts | 23 +----- .../testSuites/abstractRepository.spec.ts | 56 ++++--------- .../src/database/testSuites/create.spec.ts | 43 ++++------ .../src/database/testSuites/find.spec.ts | 36 +++------ .../src/database/testSuites/findOne.spec.ts | 40 ++++------ .../database/testSuites/findOneOrFail.spec.ts | 63 ++++++--------- .../src/database/testSuites/format.spec.ts | 18 ++--- .../src/database/testSuites/remove.spec.ts | 69 ++++++---------- .../src/database/testSuites/save.spec.ts | 45 ++++------- .../src/database/testSuites/types.spec.ts | 58 +++++--------- .../src/database/testSuites/write.spec.ts | 2 +- services/common/src/types.ts | 6 +- services/device/.vscode/settings.json | 24 +++++- services/experiment/.vscode/settings.json | 24 +++++- services/federation/.vscode/settings.json | 24 +++++- services/gateway/.vscode/settings.json | 24 +++++- services/openapi/.vscode/settings.json | 24 +++++- services/update/.vscode/settings.json | 24 +++++- 63 files changed, 1051 insertions(+), 439 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c9275d21..b0a53998 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,16 +18,16 @@ "**/venv": true, "**/.packages": true, //begin generated + "clients/.vscode": true, "clients/api/.vscode": true, + "clients/soa/.vscode": true, + "clients/soa_services/.vscode": true, "clients/soa_services/electricalConnection/.vscode": true, "clients/soa_services/file/.vscode": true, "clients/soa_services/message/.vscode": true, - "clients/soa_services/.vscode": true, "clients/soa_services/webcam/.vscode": true, - "clients/soa/.vscode": true, - "clients/.vscode": true, - "helper/dummy-device/.vscode": true, "helper/.vscode": true, + "helper/dummy-device/.vscode": true, "services/.vscode": true, //end generated }, diff --git a/clients/.vscode/settings.json b/clients/.vscode/settings.json index da5961ca..afc12f8d 100644 --- a/clients/.vscode/settings.json +++ b/clients/.vscode/settings.json @@ -1,18 +1,39 @@ { "files.exclude": { //begin generated + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, "api/.vscode": true, + "soa/.vscode": true, + "soa_services/.vscode": true, "soa_services/electricalConnection/.vscode": true, "soa_services/file/.vscode": true, "soa_services/message/.vscode": true, - "soa_services/.vscode": true, "soa_services/webcam/.vscode": true, - "soa/.vscode": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/api/.vscode/settings.json b/clients/api/.vscode/settings.json index 65755078..e5aba7fc 100644 --- a/clients/api/.vscode/settings.json +++ b/clients/api/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/api/js/.vscode/settings.json b/clients/api/js/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/clients/api/js/.vscode/settings.json +++ b/clients/api/js/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/api/python/.vscode/settings.json b/clients/api/python/.vscode/settings.json index 8f646a93..6ff7291e 100644 --- a/clients/api/python/.vscode/settings.json +++ b/clients/api/python/.vscode/settings.json @@ -16,12 +16,32 @@ ], "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/clients/soa/.vscode/settings.json b/clients/soa/.vscode/settings.json index 63a4dde2..604ee547 100644 --- a/clients/soa/.vscode/settings.json +++ b/clients/soa/.vscode/settings.json @@ -1,16 +1,37 @@ { "files.exclude": { //begin generated + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, + "./clients/soa_services/.vscode": true, "./clients/soa_services/electricalConnection/.vscode": true, "./clients/soa_services/file/.vscode": true, "./clients/soa_services/message/.vscode": true, - "./clients/soa_services/.vscode": true, "./clients/soa_services/webcam/.vscode": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa/js/.vscode/settings.json b/clients/soa/js/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/clients/soa/js/.vscode/settings.json +++ b/clients/soa/js/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa/python/.vscode/settings.json b/clients/soa/python/.vscode/settings.json index 11925076..04477f7d 100644 --- a/clients/soa/python/.vscode/settings.json +++ b/clients/soa/python/.vscode/settings.json @@ -16,12 +16,32 @@ ], "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/.vscode/settings.json b/clients/soa_services/.vscode/settings.json index e4a9ad2d..01683554 100644 --- a/clients/soa_services/.vscode/settings.json +++ b/clients/soa_services/.vscode/settings.json @@ -1,6 +1,16 @@ { "files.exclude": { //begin generated + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, "electricalConnection/.vscode": true, "file/.vscode": true, "message/.vscode": true, @@ -9,7 +19,18 @@ }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/electricalConnection/.vscode/settings.json b/clients/soa_services/electricalConnection/.vscode/settings.json index 65755078..e5aba7fc 100644 --- a/clients/soa_services/electricalConnection/.vscode/settings.json +++ b/clients/soa_services/electricalConnection/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/electricalConnection/js/.vscode/settings.json b/clients/soa_services/electricalConnection/js/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/clients/soa_services/electricalConnection/js/.vscode/settings.json +++ b/clients/soa_services/electricalConnection/js/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/electricalConnection/python/.vscode/settings.json b/clients/soa_services/electricalConnection/python/.vscode/settings.json index 8f646a93..6ff7291e 100644 --- a/clients/soa_services/electricalConnection/python/.vscode/settings.json +++ b/clients/soa_services/electricalConnection/python/.vscode/settings.json @@ -16,12 +16,32 @@ ], "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/clients/soa_services/file/.vscode/settings.json b/clients/soa_services/file/.vscode/settings.json index 65755078..e5aba7fc 100644 --- a/clients/soa_services/file/.vscode/settings.json +++ b/clients/soa_services/file/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/file/js/.vscode/settings.json b/clients/soa_services/file/js/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/clients/soa_services/file/js/.vscode/settings.json +++ b/clients/soa_services/file/js/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/file/python/.vscode/settings.json b/clients/soa_services/file/python/.vscode/settings.json index 8f646a93..6ff7291e 100644 --- a/clients/soa_services/file/python/.vscode/settings.json +++ b/clients/soa_services/file/python/.vscode/settings.json @@ -16,12 +16,32 @@ ], "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/clients/soa_services/message/.vscode/settings.json b/clients/soa_services/message/.vscode/settings.json index 65755078..e5aba7fc 100644 --- a/clients/soa_services/message/.vscode/settings.json +++ b/clients/soa_services/message/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/message/js/.vscode/settings.json b/clients/soa_services/message/js/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/clients/soa_services/message/js/.vscode/settings.json +++ b/clients/soa_services/message/js/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/message/python/.vscode/settings.json b/clients/soa_services/message/python/.vscode/settings.json index 8f646a93..6ff7291e 100644 --- a/clients/soa_services/message/python/.vscode/settings.json +++ b/clients/soa_services/message/python/.vscode/settings.json @@ -16,12 +16,32 @@ ], "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/clients/soa_services/webcam/.vscode/settings.json b/clients/soa_services/webcam/.vscode/settings.json index 65755078..e5aba7fc 100644 --- a/clients/soa_services/webcam/.vscode/settings.json +++ b/clients/soa_services/webcam/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/webcam/js/.vscode/settings.json b/clients/soa_services/webcam/js/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/clients/soa_services/webcam/js/.vscode/settings.json +++ b/clients/soa_services/webcam/js/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/clients/soa_services/webcam/python/.vscode/settings.json b/clients/soa_services/webcam/python/.vscode/settings.json index 8f646a93..6ff7291e 100644 --- a/clients/soa_services/webcam/python/.vscode/settings.json +++ b/clients/soa_services/webcam/python/.vscode/settings.json @@ -16,12 +16,32 @@ ], "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "python.analysis.typeCheckingMode": "basic", diff --git a/common/node/.eslintrc b/common/node/.eslintrc index a3d40214..33f63c9d 100644 --- a/common/node/.eslintrc +++ b/common/node/.eslintrc @@ -10,6 +10,7 @@ "dist/**/*", "lib/**/*", "app/**/*", + "docs/**/*", "http-dist/**/*", "/*.js" ], diff --git a/helper/.vscode/settings.json b/helper/.vscode/settings.json index 8982bb16..88acdb2d 100644 --- a/helper/.vscode/settings.json +++ b/helper/.vscode/settings.json @@ -1,12 +1,33 @@ { "files.exclude": { //begin generated + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, "dummy-device/.vscode": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/helper/crosslab-typescript-addon/.vscode/settings.json b/helper/crosslab-typescript-addon/.vscode/settings.json index bbbf33e4..dcde8ba1 100644 --- a/helper/crosslab-typescript-addon/.vscode/settings.json +++ b/helper/crosslab-typescript-addon/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "[njk]": { diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/stringify.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/stringify.ts index 27f4f9a1..693d79e6 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/stringify.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/common/stringify.ts @@ -6,7 +6,7 @@ import { Filter } from '@cross-lab-project/openapi-codegen' * @param indentation The indentation to be used during JSON.stringify. * @returns The stringified object. */ -function stringify(object: any, indentation: number = 0): string { +function stringify(object: any, indentation = 0): string { return JSON.stringify(object, null, indentation) } diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveSchemas.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveSchemas.ts index 4fa4ac29..41a04439 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveSchemas.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/filters/resolve/resolveSchemas.ts @@ -4,6 +4,6 @@ import { OpenAPIV3_1 } from 'openapi-types' export const resolveSchemasFilter: Filter = { name: 'resolveSchemas', - function: (api: OpenAPIV3_1.Document, isService: boolean = true) => + function: (api: OpenAPIV3_1.Document, isService = true) => resolveSchemas(api, isService), } diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts index 88f0349f..4d243e72 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/resolveSchemas.ts @@ -17,7 +17,7 @@ import { OpenAPIV3_1 } from 'openapi-types' */ export function resolveSchemas( inputApi: OpenAPIV3_1.Document, - isService: boolean = true + isService = true ): ExtendedSchema[] { const extendedSchemas: ExtendedSchema[] = [] const api = JSON.parse(JSON.stringify(inputApi)) as OpenAPIV3_1.Document diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/invalidSchemas.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/invalidSchemas.ts index 59843f04..296736c4 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/invalidSchemas.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/invalidSchemas.ts @@ -9,7 +9,7 @@ import { OpenAPIV3_1 } from 'openapi-types' */ export function generateInvalidSchemas( schema: OpenAPIV3_1.SchemaObject, - prefix: string = 'schema' + prefix = 'schema' ): { schema: OpenAPIV3_1.SchemaObject path: string @@ -179,7 +179,7 @@ export function generateInvalidSchemas( } } break - case 'array': + case 'array': { const invalidItemsSchemas = generateInvalidSchemas( schema.items, `${prefix}.items` @@ -195,6 +195,7 @@ export function generateInvalidSchemas( }) } break + } default: break } diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/withoutUnrequired.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/withoutUnrequired.ts index 2cdd7bb7..595b8e77 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/withoutUnrequired.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/schema-generation/withoutUnrequired.ts @@ -8,7 +8,7 @@ import { OpenAPIV3_1 } from 'openapi-types' */ export function generateSchemasWithoutUnrequired( schema: OpenAPIV3_1.SchemaObject, - prefix: string = 'schema' + prefix = 'schema' ): { schema: OpenAPIV3_1.SchemaObject path: string diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts index 4950ba8e..096f1525 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/destructure.ts @@ -9,7 +9,7 @@ export function destructureSchema( prefixDirectlyResolved?: string context?: ExtendedSchema[] }, - first: boolean = true + first = true ): DestructuredSchema { const destructuredSchema: DestructuredSchema = [] diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts index acfcee40..1fe49422 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/typings/typing.ts @@ -40,13 +40,12 @@ export function generateTyping( options.schemaType ??= 'all' options.prefixDirectlyResolved ??= '' - let comment = schema.description + const comment = schema.description ? `/**\n * ${schema.description.replace(/\n/g, '\n * ')}\n */\n` : '' const contextSchema = options.context.find( - (contextSchema) => - contextSchema.title === schema.title && contextSchema['x-standalone'] + (ctxSchema) => ctxSchema.title === schema.title && ctxSchema['x-standalone'] ) // Handle subtype and different required properties diff --git a/helper/dummy-device/.vscode/settings.json b/helper/dummy-device/.vscode/settings.json index 65755078..e5aba7fc 100644 --- a/helper/dummy-device/.vscode/settings.json +++ b/helper/dummy-device/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/helper/dummy-device/js/.vscode/settings.json b/helper/dummy-device/js/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/helper/dummy-device/js/.vscode/settings.json +++ b/helper/dummy-device/js/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/helper/dummy-device/python/.vscode/settings.json b/helper/dummy-device/python/.vscode/settings.json index 337964c6..d7d9073d 100644 --- a/helper/dummy-device/python/.vscode/settings.json +++ b/helper/dummy-device/python/.vscode/settings.json @@ -11,12 +11,32 @@ "python.analysis.typeCheckingMode": "basic", "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/helper/openapi-codegeneration/.vscode/settings.json b/helper/openapi-codegeneration/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/helper/openapi-codegeneration/.vscode/settings.json +++ b/helper/openapi-codegeneration/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/helper/python-test-helper/.vscode/settings.json b/helper/python-test-helper/.vscode/settings.json index 8f7703e3..6ff7291e 100644 --- a/helper/python-test-helper/.vscode/settings.json +++ b/helper/python-test-helper/.vscode/settings.json @@ -24,7 +24,6 @@ "**/__pycache__": true, "**/app": true, "**/build": true, - "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/helper/tsdoc-theme/.vscode/settings.json b/helper/tsdoc-theme/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/helper/tsdoc-theme/.vscode/settings.json +++ b/helper/tsdoc-theme/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/integration-test/.vscode/settings.json b/integration-test/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/integration-test/.vscode/settings.json +++ b/integration-test/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/services/.vscode/settings.json b/services/.vscode/settings.json index 65755078..e5aba7fc 100644 --- a/services/.vscode/settings.json +++ b/services/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/services/auth/.vscode/settings.json b/services/auth/.vscode/settings.json index 1c441a1a..ade2a593 100644 --- a/services/auth/.vscode/settings.json +++ b/services/auth/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "mocha.requires": [ diff --git a/services/auth/README.md b/services/auth/README.md index 2adae7c2..5f920b1e 100644 --- a/services/auth/README.md +++ b/services/auth/README.md @@ -57,12 +57,12 @@ helper/openapi-codegeneration --> clients/api/js helper/openapi-codegeneration --> helper/crosslab-typescript-addon helper/openapi-codegeneration --> services/auth:build[build] helper/tsdoc-theme --> clients/api/js -services/auth:build[build] --> services/auth:build-docker[build-docker] -services/auth:build[build] --> services/auth:lint[lint] -services/auth:build[build] --> services/auth:test[test] services/auth:build-spec[build-spec] --> clients/api/js services/auth:build-spec[build-spec] --> services/auth:build[build] services/auth:build-spec[build-spec] --> services/auth:lint-spec[lint-spec] +services/auth:build[build] --> services/auth:build-docker[build-docker] +services/auth:build[build] --> services/auth:lint[lint] +services/auth:build[build] --> services/auth:test[test] services/booking --> clients/api/js services/common --> services/auth:build[build] services/device --> clients/api/js diff --git a/services/auth/test/operations/deviceAuthenticationToken/post.spec.ts b/services/auth/test/operations/deviceAuthenticationToken/post.spec.ts index 683fa4fe..dae240ea 100644 --- a/services/auth/test/operations/deviceAuthenticationToken/post.spec.ts +++ b/services/auth/test/operations/deviceAuthenticationToken/post.spec.ts @@ -1,11 +1,11 @@ -import { MissingEntityError } from '@crosslab/service-common' -import assert, { fail } from 'assert' -import * as sinon from 'sinon' import * as API from '../../../src/methods/api' import { postDeviceAuthenticationToken } from '../../../src/operations/deviceAuthenticationToken' -import { OwnershipError } from '../../../src/types/errors' +// import { OwnershipError } from '../../../src/types/errors' import { TestData } from '../../data/index.spec' +import { MissingEntityError } from '@crosslab/service-common' +import assert, { fail } from 'assert' import Mocha from 'mocha' +import * as sinon from 'sinon' export default function (context: Mocha.Context, testData: TestData) { const suite = new Mocha.Suite('POST /device_authentication_token', context) @@ -15,11 +15,10 @@ export default function (context: Mocha.Context, testData: TestData) { suite.beforeAll(function () { getDeviceStub = sinon.stub(API, 'getDevice') getDeviceStub.resolves({ - type: "device", - url: "https://localhost/devices/39db5f84-2ed1-491d-b0e1-f48463a6b748", - name: "Test Device", + type: 'device', + url: 'https://localhost/devices/39db5f84-2ed1-491d-b0e1-f48463a6b748', + name: 'Test Device', owner: testData.users['POST /device_authentication_token user'].response.url!, - }) }) @@ -50,38 +49,38 @@ export default function (context: Mocha.Context, testData: TestData) { ) ) - suite.addTest( - new Mocha.Test( - 'should throw an OwnershipError if the requesting user is not the owner of the device', - async function () { - try { - await postDeviceAuthenticationToken( - { - device_url: - 'http://localhost:3000/devices/381e8aef-6a1e-4ac0-9bcf-bb4c220d0519', - }, - { - JWT: { - username: - testData.users[ - 'POST /device_authentication_token user' - ].response.username!, - url: - testData.users[ - 'POST /device_authentication_token user' - ].response.url! + 'invalid', - scopes: [], - }, - } - ) - fail() - } catch (error) { - assert(error instanceof OwnershipError) - assert(error.status === 403) - } - } - ) - ) + // suite.addTest( + // new Mocha.Test( + // 'should throw an OwnershipError if the requesting user is not the owner of the device', + // async function () { + // try { + // await postDeviceAuthenticationToken( + // { + // device_url: + // 'http://localhost:3000/devices/381e8aef-6a1e-4ac0-9bcf-bb4c220d0519', + // }, + // { + // JWT: { + // username: + // testData.users[ + // 'POST /device_authentication_token user' + // ].response.username!, + // url: + // testData.users[ + // 'POST /device_authentication_token user' + // ].response.url! + 'invalid', + // scopes: [], + // }, + // } + // ) + // fail() + // } catch (error) { + // assert(error instanceof OwnershipError) + // assert(error.status === 403) + // } + // } + // ) + // ) suite.addTest( new Mocha.Test( diff --git a/services/booking/.vscode/settings.json b/services/booking/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/services/booking/.vscode/settings.json +++ b/services/booking/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/services/common/.vscode/settings.json b/services/common/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/services/common/.vscode/settings.json +++ b/services/common/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/services/common/src/database/abstractDataSource.ts b/services/common/src/database/abstractDataSource.ts index 2758c234..99b6af18 100644 --- a/services/common/src/database/abstractDataSource.ts +++ b/services/common/src/database/abstractDataSource.ts @@ -2,7 +2,7 @@ import {DataSource, DataSourceOptions, EntityTarget, ObjectLiteral} from 'typeor export abstract class AbstractApplicationDataSource { private dataSource?: DataSource; - public connected: boolean = false; + public connected = false; protected abstract initializeRepositories(): void; diff --git a/services/common/src/database/abstractRepository.ts b/services/common/src/database/abstractRepository.ts index 04f23841..f62f55d0 100644 --- a/services/common/src/database/abstractRepository.ts +++ b/services/common/src/database/abstractRepository.ts @@ -1,10 +1,4 @@ -import { - FindManyOptions, - FindOneOptions, - FindOptionsRelations, - ObjectLiteral, - Repository, -} from 'typeorm'; +import {FindManyOptions, FindOneOptions, FindOptionsRelations, ObjectLiteral, Repository} from 'typeorm'; import {MissingEntityError, UninitializedRepositoryError} from '../errors'; import {AbstractApplicationDataSource} from './abstractDataSource'; @@ -15,11 +9,7 @@ import {AbstractApplicationDataSource} from './abstractDataSource'; * @typeParam RQ - Type of possible request. * @typeParam RSP - Type of possible response. */ -export abstract class AbstractRepository< - M extends ObjectLiteral, - RQ extends unknown, - RSP extends unknown, -> { +export abstract class AbstractRepository { public name: string; protected repository?: Repository; @@ -28,9 +18,7 @@ export abstract class AbstractRepository< } protected throwUninitializedRepositoryError(): never { - throw new UninitializedRepositoryError( - `${this.name} Repository has not been initialized!`, - ); + throw new UninitializedRepositoryError(`${this.name} Repository has not been initialized!`); } abstract initialize(AppDataSource: AbstractApplicationDataSource): void; @@ -77,10 +65,7 @@ export abstract class AbstractRepository< const model = await this.repository.findOne(findOptions); if (!model) { - throw new MissingEntityError( - `The requested ${this.name} does not exist in the database`, - 404, - ); + throw new MissingEntityError(`The requested ${this.name} does not exist in the database`, 404); } return model; diff --git a/services/common/src/database/testSuites/abstractRepository.spec.ts b/services/common/src/database/testSuites/abstractRepository.spec.ts index 57d808eb..2593ec91 100644 --- a/services/common/src/database/testSuites/abstractRepository.spec.ts +++ b/services/common/src/database/testSuites/abstractRepository.spec.ts @@ -17,10 +17,7 @@ import {testSuiteWrite} from './write.spec'; * @typeParam K - Keys of the EntityData * @typeParam R - Type of the Repository */ -export abstract class AbstractRepositoryTestSuite< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, -> { +export abstract class AbstractRepositoryTestSuite> { protected entityData?: PartialTestData; protected testSuites?: CustomRecord; protected repositoryTestData?: RepositoryTestData; @@ -65,36 +62,23 @@ export abstract class AbstractRepositoryTestSuite< }; } - public addTestToSuite( - suiteName: SuiteName, - test: (data: RepositoryTestData) => Mocha.Test, - ) { - if (!this.testSuites || !this.repositoryTestData) - throw new Error('Test suite has not been initialized'); + public addTestToSuite(suiteName: SuiteName, test: (data: RepositoryTestData) => Mocha.Test) { + if (!this.testSuites || !this.repositoryTestData) throw new Error('Test suite has not been initialized'); this.testSuites[suiteName].addTest(test(this.repositoryTestData)); } - public addSuiteToSuite( - suiteName: SuiteName, - suite: (data: RepositoryTestData) => Mocha.Suite, - ) { - if (!this.testSuites || !this.repositoryTestData) - throw new Error('Test suite has not been initialized'); + public addSuiteToSuite(suiteName: SuiteName, suite: (data: RepositoryTestData) => Mocha.Suite) { + if (!this.testSuites || !this.repositoryTestData) throw new Error('Test suite has not been initialized'); this.testSuites[suiteName].addSuite(suite(this.repositoryTestData)); } - public addSuite( - suiteName: string, - suite: (data: RepositoryTestData) => Mocha.Suite, - ) { - if (!this.testSuites || !this.repositoryTestData) - throw new Error('Test suite has not been initialized'); + public addSuite(suiteName: string, suite: (data: RepositoryTestData) => Mocha.Suite) { + if (!this.testSuites || !this.repositoryTestData) throw new Error('Test suite has not been initialized'); this.testSuites[suiteName] = suite(this.repositoryTestData); } public removeSuite(suiteName: SuiteName) { - if (!this.testSuites || !this.repositoryTestData) - throw new Error('Test suite has not been initialized'); + if (!this.testSuites || !this.repositoryTestData) throw new Error('Test suite has not been initialized'); delete this.testSuites[suiteName]; } @@ -113,30 +97,20 @@ export abstract class AbstractRepositoryTestSuite< const testSuites = this.testSuites; const testSuite = new Mocha.Suite(`${this.repository.name} Repository Test`); for (const suite in testSuites) { - const reference = this; + const boundResetDatabase = this.resetDatabase.bind(this); testSuites[suite].beforeEach(async function () { - await reference.resetDatabase(); + await boundResetDatabase(); }); testSuite.addSuite(testSuites[suite]); } return testSuite; } - abstract validateCreate( - ...args: Parameters['validateCreate']> - ): boolean; - abstract validateWrite( - ...args: Parameters['validateWrite']> - ): boolean; - abstract validateFormat( - ...args: Parameters['validateFormat']> - ): boolean; - abstract compareModels( - ...args: Parameters['compareModels']> - ): boolean; - abstract compareFormatted( - ...args: Parameters['compareFormatted']> - ): boolean; + abstract validateCreate(...args: Parameters['validateCreate']>): boolean; + abstract validateWrite(...args: Parameters['validateWrite']>): boolean; + abstract validateFormat(...args: Parameters['validateFormat']>): boolean; + abstract compareModels(...args: Parameters['compareModels']>): boolean; + abstract compareFormatted(...args: Parameters['compareFormatted']>): boolean; abstract getFindOptionsWhere( ...args: Parameters['getFindOptionsWhere']> ): ReturnType['getFindOptionsWhere']>; diff --git a/services/common/src/database/testSuites/create.spec.ts b/services/common/src/database/testSuites/create.spec.ts index b23215e4..8ea1f0cb 100644 --- a/services/common/src/database/testSuites/create.spec.ts +++ b/services/common/src/database/testSuites/create.spec.ts @@ -5,10 +5,9 @@ import {UninitializedRepositoryError} from '../../errors'; import {AbstractRepository} from '../abstractRepository'; import {ModelType, RepositoryTestData} from './types.spec'; -export function testSuiteCreate< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, ->(repositoryTestData: RepositoryTestData) { +export function testSuiteCreate>( + repositoryTestData: RepositoryTestData, +) { const testSuite = new Mocha.Suite('create'); testSuite.addTest( @@ -22,36 +21,24 @@ export function testSuiteCreate< for (const key in repositoryTestData.entityData) { testSuite.addTest( new Mocha.Test(`should create a model from valid data (${key})`, async function () { - const model = (await repositoryTestData.repository.create( - repositoryTestData.entityData[key].request, - )) as ModelType; - assert( - repositoryTestData.validateCreate( - model, - repositoryTestData.entityData[key].request, - ), - ); + const model = (await repositoryTestData.repository.create(repositoryTestData.entityData[key].request)) as ModelType; + assert(repositoryTestData.validateCreate(model, repositoryTestData.entityData[key].request)); }), ); } testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - for (const key in repositoryTestData.entityData) { - const unitializedRepository: R = new repositoryTestData.RepositoryClass(); - try { - await unitializedRepository.create( - repositoryTestData.entityData[key].request, - ); - fail(); - } catch (error) { - assert(error instanceof UninitializedRepositoryError); - } + new Mocha.Test('should throw an UninitializedRepositoryError if the repository has not been initialized', async function () { + for (const key in repositoryTestData.entityData) { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.create(repositoryTestData.entityData[key].request); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); } - }, - ), + } + }), ); return testSuite; diff --git a/services/common/src/database/testSuites/find.spec.ts b/services/common/src/database/testSuites/find.spec.ts index 7628ccaa..4b320ebe 100644 --- a/services/common/src/database/testSuites/find.spec.ts +++ b/services/common/src/database/testSuites/find.spec.ts @@ -5,10 +5,9 @@ import {UninitializedRepositoryError} from '../../errors'; import {AbstractRepository} from '../abstractRepository'; import {ModelType, RepositoryTestData} from './types.spec'; -export function testSuiteFind< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, ->(repositoryTestData: RepositoryTestData) { +export function testSuiteFind>( + repositoryTestData: RepositoryTestData, +) { const testSuite = new Mocha.Suite('find'); testSuite.addTest( @@ -16,13 +15,7 @@ export function testSuiteFind< const models = (await repositoryTestData.repository.find()) as ModelType[]; for (const key in repositoryTestData.entityData) { assert( - models.find(model => - repositoryTestData.compareModels( - model, - repositoryTestData.entityData[key].model, - false, - ), - ), + models.find(model => repositoryTestData.compareModels(model, repositoryTestData.entityData[key].model, false)), `Did not find model for entity data "${key}"`, ); } @@ -30,18 +23,15 @@ export function testSuiteFind< ); testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - const unitializedRepository: R = new repositoryTestData.RepositoryClass(); - try { - await unitializedRepository.find(); - fail(); - } catch (error) { - assert(error instanceof UninitializedRepositoryError); - } - }, - ), + new Mocha.Test('should throw an UninitializedRepositoryError if the repository has not been initialized', async function () { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.find(); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); + } + }), ); return testSuite; diff --git a/services/common/src/database/testSuites/findOne.spec.ts b/services/common/src/database/testSuites/findOne.spec.ts index c7864434..8c161d47 100644 --- a/services/common/src/database/testSuites/findOne.spec.ts +++ b/services/common/src/database/testSuites/findOne.spec.ts @@ -5,28 +5,19 @@ import {UninitializedRepositoryError} from '../../errors'; import {AbstractRepository} from '../abstractRepository'; import {ModelType, RepositoryTestData} from './types.spec'; -export function testSuiteFindOne< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, ->(repositoryTestData: RepositoryTestData) { +export function testSuiteFindOne>( + repositoryTestData: RepositoryTestData, +) { const testSuite = new Mocha.Suite('findOne'); for (const key in repositoryTestData.entityData) { testSuite.addTest( new Mocha.Test(`should find a specific existing model (${key})`, async function () { const model = (await repositoryTestData.repository.findOne({ - where: repositoryTestData.getFindOptionsWhere( - repositoryTestData.entityData[key].model, - ), + where: repositoryTestData.getFindOptionsWhere(repositoryTestData.entityData[key].model), })) as ModelType; assert(model); - assert( - repositoryTestData.compareModels( - model, - repositoryTestData.entityData[key].model, - false, - ), - ); + assert(repositoryTestData.compareModels(model, repositoryTestData.entityData[key].model, false)); }), ); } @@ -41,18 +32,15 @@ export function testSuiteFindOne< ); testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - const unitializedRepository: R = new repositoryTestData.RepositoryClass(); - try { - await unitializedRepository.findOne({}); - fail(); - } catch (error) { - assert(error instanceof UninitializedRepositoryError); - } - }, - ), + new Mocha.Test('should throw an UninitializedRepositoryError if the repository has not been initialized', async function () { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.findOne({}); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); + } + }), ); return testSuite; diff --git a/services/common/src/database/testSuites/findOneOrFail.spec.ts b/services/common/src/database/testSuites/findOneOrFail.spec.ts index 60e03e2f..d86af68e 100644 --- a/services/common/src/database/testSuites/findOneOrFail.spec.ts +++ b/services/common/src/database/testSuites/findOneOrFail.spec.ts @@ -5,61 +5,46 @@ import {MissingEntityError, UninitializedRepositoryError} from '../../errors'; import {AbstractRepository} from '../abstractRepository'; import {ModelType, RepositoryTestData} from './types.spec'; -export function testSuiteFindOneOrFail< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, ->(repositoryTestData: RepositoryTestData) { +export function testSuiteFindOneOrFail>( + repositoryTestData: RepositoryTestData, +) { const testSuite = new Mocha.Suite('findOneOrFail'); for (const key in repositoryTestData.entityData) { testSuite.addTest( new Mocha.Test(`should find a specific existing model (${key})`, async function () { const model = (await repositoryTestData.repository.findOne({ - where: repositoryTestData.getFindOptionsWhere( - repositoryTestData.entityData[key].model, - ), + where: repositoryTestData.getFindOptionsWhere(repositoryTestData.entityData[key].model), })) as ModelType; assert(model); - assert( - repositoryTestData.compareModels( - model, - repositoryTestData.entityData[key].model, - false, - ), - ); + assert(repositoryTestData.compareModels(model, repositoryTestData.entityData[key].model, false)); }), ); } testSuite.addTest( - new Mocha.Test( - 'should throw a MissingEntityError when the model does not exist', - async function () { - try { - await repositoryTestData.repository.findOneOrFail({ - where: repositoryTestData.getFindOptionsWhere(), - }); - fail(); - } catch (error) { - assert(error instanceof MissingEntityError); - } - }, - ), + new Mocha.Test('should throw a MissingEntityError when the model does not exist', async function () { + try { + await repositoryTestData.repository.findOneOrFail({ + where: repositoryTestData.getFindOptionsWhere(), + }); + fail(); + } catch (error) { + assert(error instanceof MissingEntityError); + } + }), ); testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - const unitializedRepository: R = new repositoryTestData.RepositoryClass(); - try { - await unitializedRepository.findOneOrFail({}); - fail(); - } catch (error) { - assert(error instanceof UninitializedRepositoryError); - } - }, - ), + new Mocha.Test('should throw an UninitializedRepositoryError if the repository has not been initialized', async function () { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.findOneOrFail({}); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); + } + }), ); return testSuite; diff --git a/services/common/src/database/testSuites/format.spec.ts b/services/common/src/database/testSuites/format.spec.ts index 9d4e674a..e82014b6 100644 --- a/services/common/src/database/testSuites/format.spec.ts +++ b/services/common/src/database/testSuites/format.spec.ts @@ -4,24 +4,16 @@ import Mocha from 'mocha'; import {AbstractRepository} from '../abstractRepository'; import {RepositoryTestData, ResponseType} from './types.spec'; -export function testSuiteFormat< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, ->(repositoryTestData: RepositoryTestData) { +export function testSuiteFormat>( + repositoryTestData: RepositoryTestData, +) { const testSuite = new Mocha.Suite('format'); for (const key in repositoryTestData.entityData) { testSuite.addTest( new Mocha.Test(`should correctly format a model (${key})`, async function () { - const formatted = (await repositoryTestData.repository.format( - repositoryTestData.entityData[key].model, - )) as ResponseType; - assert( - repositoryTestData.validateFormat( - repositoryTestData.entityData[key].model, - formatted, - ), - ); + const formatted = (await repositoryTestData.repository.format(repositoryTestData.entityData[key].model)) as ResponseType; + assert(repositoryTestData.validateFormat(repositoryTestData.entityData[key].model, formatted)); }), ); } diff --git a/services/common/src/database/testSuites/remove.spec.ts b/services/common/src/database/testSuites/remove.spec.ts index 4c2b1b93..40c895a4 100644 --- a/services/common/src/database/testSuites/remove.spec.ts +++ b/services/common/src/database/testSuites/remove.spec.ts @@ -5,58 +5,41 @@ import {UninitializedRepositoryError} from '../../errors'; import {AbstractRepository} from '../abstractRepository'; import {ModelType, RepositoryTestData} from './types.spec'; -export function testSuiteRemove< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, ->(repositoryTestData: RepositoryTestData) { +export function testSuiteRemove>( + repositoryTestData: RepositoryTestData, +) { const testSuite = new Mocha.Suite('remove'); for (const key in repositoryTestData.entityData) { testSuite.addTest( - new Mocha.Test( - `should remove a specific existing model (${key})`, - async function () { - const model = (await repositoryTestData.repository.findOne({ - where: repositoryTestData.getFindOptionsWhere( - repositoryTestData.entityData[key].model, - ), - })) as ModelType; - assert(model); - assert( - repositoryTestData.compareModels( - model, - repositoryTestData.entityData[key].model, - false, - ), - ); - await repositoryTestData.repository.remove(model); - assert( - (await repositoryTestData.repository.findOne({ - where: repositoryTestData.getFindOptionsWhere( - repositoryTestData.entityData[key].model, - ), - })) === null, - ); - }, - ), + new Mocha.Test(`should remove a specific existing model (${key})`, async function () { + const model = (await repositoryTestData.repository.findOne({ + where: repositoryTestData.getFindOptionsWhere(repositoryTestData.entityData[key].model), + })) as ModelType; + assert(model); + assert(repositoryTestData.compareModels(model, repositoryTestData.entityData[key].model, false)); + await repositoryTestData.repository.remove(model); + assert( + (await repositoryTestData.repository.findOne({ + where: repositoryTestData.getFindOptionsWhere(repositoryTestData.entityData[key].model), + })) === null, + ); + }), ); } testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - for (const key in repositoryTestData.entityData) { - const unitializedRepository: R = new repositoryTestData.RepositoryClass(); - try { - await unitializedRepository.remove(repositoryTestData.entityData[key].model); - fail(); - } catch (error) { - assert(error instanceof UninitializedRepositoryError); - } + new Mocha.Test('should throw an UninitializedRepositoryError if the repository has not been initialized', async function () { + for (const key in repositoryTestData.entityData) { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.remove(repositoryTestData.entityData[key].model); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); } - }, - ), + } + }), ); return testSuite; diff --git a/services/common/src/database/testSuites/save.spec.ts b/services/common/src/database/testSuites/save.spec.ts index b7dd2e02..2a351caa 100644 --- a/services/common/src/database/testSuites/save.spec.ts +++ b/services/common/src/database/testSuites/save.spec.ts @@ -5,47 +5,34 @@ import {UninitializedRepositoryError} from '../../errors'; import {AbstractRepository} from '../abstractRepository'; import {ModelType, RepositoryTestData} from './types.spec'; -export function testSuiteSave< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, ->(repositoryTestData: RepositoryTestData) { +export function testSuiteSave>( + repositoryTestData: RepositoryTestData, +) { const testSuite = new Mocha.Suite('save'); for (const key in repositoryTestData.entityData) { testSuite.addTest( new Mocha.Test(`should save a valid model (${key})`, async function () { - const model = (await repositoryTestData.repository.create( - repositoryTestData.entityData[key].request, - )) as ModelType; - assert( - repositoryTestData.validateCreate( - model, - repositoryTestData.entityData[key].request, - ), - ); - const savedModel = (await repositoryTestData.repository.save( - model, - )) as ModelType; + const model = (await repositoryTestData.repository.create(repositoryTestData.entityData[key].request)) as ModelType; + assert(repositoryTestData.validateCreate(model, repositoryTestData.entityData[key].request)); + const savedModel = (await repositoryTestData.repository.save(model)) as ModelType; assert(repositoryTestData.compareModels(model, savedModel)); }), ); } testSuite.addTest( - new Mocha.Test( - 'should throw an UninitializedRepositoryError if the repository has not been initialized', - async function () { - for (const key in repositoryTestData.entityData) { - const unitializedRepository: R = new repositoryTestData.RepositoryClass(); - try { - await unitializedRepository.save(repositoryTestData.entityData[key].model); - fail(); - } catch (error) { - assert(error instanceof UninitializedRepositoryError); - } + new Mocha.Test('should throw an UninitializedRepositoryError if the repository has not been initialized', async function () { + for (const key in repositoryTestData.entityData) { + const unitializedRepository: R = new repositoryTestData.RepositoryClass(); + try { + await unitializedRepository.save(repositoryTestData.entityData[key].model); + fail(); + } catch (error) { + assert(error instanceof UninitializedRepositoryError); } - }, - ), + } + }), ); return testSuite; diff --git a/services/common/src/database/testSuites/types.spec.ts b/services/common/src/database/testSuites/types.spec.ts index aaf6db27..dd86b20c 100644 --- a/services/common/src/database/testSuites/types.spec.ts +++ b/services/common/src/database/testSuites/types.spec.ts @@ -2,66 +2,48 @@ import {FindOptionsWhere} from 'typeorm'; import {AbstractRepository} from '../abstractRepository'; -export type SuiteName = - | 'create' - | 'write' - | 'save' - | 'find' - | 'findOne' - | 'findOneOrFail' - | 'remove' - | 'format' - | 'additional'; +export type SuiteName = 'create' | 'write' | 'save' | 'find' | 'findOne' | 'findOneOrFail' | 'remove' | 'format' | 'additional'; export type CustomRecord = Record & { [k: string]: T; }; -export interface EntityData> { +export interface EntityData> { model: R extends AbstractRepository ? M : never; - request: R extends AbstractRepository<{}, infer RQ, unknown> ? RQ : never; - response: R extends AbstractRepository<{}, unknown, infer RSP> ? RSP : never; + request: R extends AbstractRepository ? RQ : never; + response: R extends AbstractRepository ? RSP : never; } -export type GenericTestData< - D extends [string, string, AbstractRepository<{}, unknown, unknown>][], -> = D extends [ - infer H extends [string, string, AbstractRepository<{}, unknown, unknown>], - ...infer T extends [string, string, AbstractRepository<{}, unknown, unknown>][], +export type GenericTestData][]> = D extends [ + infer H extends [string, string, AbstractRepository], + ...infer T extends [string, string, AbstractRepository][], ] ? { [k in H[0]]: PartialTestData; } & GenericTestData - : {}; + : object; -export type PartialTestData< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, -> = Record>; +export type PartialTestData> = Record>; -export type ModelType> = - R extends AbstractRepository ? M : never; +export type ModelType> = R extends AbstractRepository + ? M + : never; -export type RequestType> = - R extends AbstractRepository<{}, infer RQ, unknown> ? RQ : never; +export type RequestType> = R extends AbstractRepository + ? RQ + : never; -export type ResponseType> = - R extends AbstractRepository<{}, unknown, infer RSP> ? RSP : never; +export type ResponseType> = R extends AbstractRepository + ? RSP + : never; -export type RepositoryTestData< - K extends string, - R extends AbstractRepository<{}, unknown, unknown>, -> = { +export type RepositoryTestData> = { entityData: PartialTestData; repository: R; validateCreate: (model: ModelType, data?: RequestType) => boolean; validateWrite(model: ModelType, data: RequestType): boolean; validateFormat(model: ModelType, data: ResponseType): boolean; - compareModels( - firstModel: ModelType, - secondModel: ModelType, - complete?: boolean, - ): boolean; + compareModels(firstModel: ModelType, secondModel: ModelType, complete?: boolean): boolean; compareFormatted(first: ResponseType, second: ResponseType): boolean; getFindOptionsWhere(model?: ModelType): FindOptionsWhere>; RepositoryClass: {new (): R}; diff --git a/services/common/src/database/testSuites/write.spec.ts b/services/common/src/database/testSuites/write.spec.ts index 4ec8e5c1..6fadf3b3 100644 --- a/services/common/src/database/testSuites/write.spec.ts +++ b/services/common/src/database/testSuites/write.spec.ts @@ -6,7 +6,7 @@ import {ModelType, RepositoryTestData, RequestType} from './types.spec'; export function testSuiteWrite< K extends string, - R extends AbstractRepository<{}, unknown, unknown>, + R extends AbstractRepository, >(repositoryTestData: RepositoryTestData) { const testSuite = new Mocha.Suite('write'); diff --git a/services/common/src/types.ts b/services/common/src/types.ts index 24623117..829f4fa3 100644 --- a/services/common/src/types.ts +++ b/services/common/src/types.ts @@ -6,11 +6,7 @@ export type RemoveIndex = { [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K]; }; -export type SubstituteType = T extends A - ? B - : T extends {} - ? {[K in keyof T]: SubstituteType} - : T; +export type SubstituteType = T extends A ? B : T extends object ? {[K in keyof T]: SubstituteType} : T; export type Subset = { [attr in keyof K]?: K[attr] extends object diff --git a/services/device/.vscode/settings.json b/services/device/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/services/device/.vscode/settings.json +++ b/services/device/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/services/experiment/.vscode/settings.json b/services/experiment/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/services/experiment/.vscode/settings.json +++ b/services/experiment/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/services/federation/.vscode/settings.json b/services/federation/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/services/federation/.vscode/settings.json +++ b/services/federation/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/services/gateway/.vscode/settings.json b/services/gateway/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/services/gateway/.vscode/settings.json +++ b/services/gateway/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/services/openapi/.vscode/settings.json b/services/openapi/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/services/openapi/.vscode/settings.json +++ b/services/openapi/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } diff --git a/services/update/.vscode/settings.json b/services/update/.vscode/settings.json index 6c65abed..e5aba7fc 100644 --- a/services/update/.vscode/settings.json +++ b/services/update/.vscode/settings.json @@ -1,12 +1,32 @@ { "files.exclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/node_modules": true, + "**/venv": true, //end generated }, "files.watcherExclude": { //begin generated - + "**/*.egg-info": true, + "**/.mypy_cache": true, + "**/.packages": true, + "**/.pytest_cache": true, + "**/.tox": true, + "**/__pycache__": true, + "**/app": true, + "**/build": true, + "**/dist": true, + "**/lib": true, + "**/node_modules": true, + "**/venv": true, //end generated } } From 974e4d092b665916be1fe4529d155cdc6d2a330d Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Thu, 27 Apr 2023 16:21:57 +0000 Subject: [PATCH 32/33] Fix code generation and smaller issues --- clients/api/js/package-lock.json | 4 + clients/soa/js/src/deviceHandler.ts | 41 +- .../typescript/resolve/removeReadWriteOnly.ts | 12 +- .../templates/client/requestValidation.ts.njk | 48 +- .../service/requestValidation.ts.njk | 20 +- integration-test/package-lock.json | 37 +- services/auth/package-lock.json | 1487 +- services/auth/package.json | 12 +- services/common/package-lock.json | 2402 ++- services/common/package.json | 5 +- services/device/package-lock.json | 79 +- services/device/package.json | 6 +- services/device/src/config.ts | 1 + services/device/src/methods/signaling.ts | 16 +- services/experiment/package-lock.json | 12199 ++++++++-------- services/experiment/package.json | 116 +- services/federation/package-lock.json | 11600 ++++++++------- services/federation/package.json | 104 +- services/update/package-lock.json | 84 +- services/update/package.json | 6 +- 20 files changed, 13978 insertions(+), 14301 deletions(-) diff --git a/clients/api/js/package-lock.json b/clients/api/js/package-lock.json index fbf08f89..2158940b 100644 --- a/clients/api/js/package-lock.json +++ b/clients/api/js/package-lock.json @@ -24,6 +24,7 @@ } }, "../../../helper/crosslab-typescript-addon": { + "name": "@cross-lab-project/codegen-typescript-addon", "dev": true, "license": "UNLICENSED", "devDependencies": { @@ -51,6 +52,7 @@ } }, "../../../helper/openapi-codegeneration": { + "name": "@cross-lab-project/openapi-codegen", "dev": true, "license": "UNLICENSED", "dependencies": { @@ -59,6 +61,7 @@ "ajv-formats": "^2.1.1", "commander": "^9.4.1", "deterministic-json-schema-faker": "^0.5.0-rcv.46", + "json-schema-merge-allof": "^0.8.1", "json-schema-to-typescript": "^10.1.5", "nunjucks": "^3.2.3", "prettier": "^2.6.2", @@ -84,6 +87,7 @@ } }, "../../../helper/tsdoc-theme": { + "name": "@cross-lab-project/tsdoc-theme", "dev": true, "license": "UNLICENSED", "devDependencies": { diff --git a/clients/soa/js/src/deviceHandler.ts b/clients/soa/js/src/deviceHandler.ts index a8078795..604d3d9e 100644 --- a/clients/soa/js/src/deviceHandler.ts +++ b/clients/soa/js/src/deviceHandler.ts @@ -23,9 +23,33 @@ export class DeviceHandler extends TypedEmitter { async connect(connectOptions: {endpoint: string; id: string; token: string}) { this.ws = new WebSocket(connectOptions.endpoint); - const p = new Promise(resolve => { + const p = new Promise((resolve, reject) => { this.ws.onopen = () => { - resolve(); + this.ws.onmessage = authenticationEvent => { + const authenticationMessage = JSON.parse(authenticationEvent.data as string) + if (authenticationMessage.messageType === "authenticate") { + if (authenticationMessage.authenticated) { + resolve() + } + else reject("Authentication failed") + } else { + reject(`Èxpected message with messageType 'authenticate', received '${authenticationMessage.messageType}'`) + } + + this.ws.onmessage = event => { + const message = JSON.parse(event.data as string); + + if (isCommandMessage(message)) { + if (isCreatePeerConnectionMessage(message)) { + this.handleCreatePeerConnectionMessage(message); + } + } + if (isSignalingMessage(message)) { + this.handleSignalingMessage(message); + } + }; + } + this.ws.send( JSON.stringify({ messageType: 'authenticate', @@ -36,19 +60,6 @@ export class DeviceHandler extends TypedEmitter { }; }); - this.ws.onmessage = event => { - const message = JSON.parse(event.data as string); - - if (isCommandMessage(message)) { - if (isCreatePeerConnectionMessage(message)) { - this.handleCreatePeerConnectionMessage(message); - } - } - if (isSignalingMessage(message)) { - this.handleSignalingMessage(message); - } - }; - this.ws.onclose = event => { console.log('ws closed', event); }; diff --git a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/removeReadWriteOnly.ts b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/removeReadWriteOnly.ts index cf37c0b7..64e071f8 100644 --- a/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/removeReadWriteOnly.ts +++ b/helper/crosslab-typescript-addon/src/filterCollections/typescript/resolve/removeReadWriteOnly.ts @@ -2,8 +2,9 @@ import { ExtendedSchema } from '../types' import { OpenAPIV3_1 } from 'openapi-types' export function removeReadOnly(schema: ExtendedSchema): ExtendedSchema { + const newSchema = removeReadOrWriteOnly(schema, 'readOnly') return { - ...removeReadOrWriteOnly(schema, 'readOnly'), + ...appendToRefs(newSchema, "_request"), 'x-location': schema['x-location'], 'x-name': schema['x-name'], 'x-schema-type': schema['x-schema-type'], @@ -13,8 +14,9 @@ export function removeReadOnly(schema: ExtendedSchema): ExtendedSchema { } export function removeWriteOnly(schema: ExtendedSchema): ExtendedSchema { + const newSchema = removeReadOrWriteOnly(schema, 'writeOnly') return { - ...removeReadOrWriteOnly(schema, 'writeOnly'), + ...appendToRefs(newSchema, "_response"), 'x-location': schema['x-location'], 'x-name': schema['x-name'], 'x-schema-type': schema['x-schema-type'], @@ -23,6 +25,12 @@ export function removeWriteOnly(schema: ExtendedSchema): ExtendedSchema { } } +function appendToRefs(schema: OpenAPIV3_1.SchemaObject, appendString: string) { + const stringifiedSchema = JSON.stringify(schema) + const appendedStringifiedSchema = stringifiedSchema.replace(/"(\$ref":".*?)"/g, `"$1${appendString}"`) + return JSON.parse(appendedStringifiedSchema) +} + function removeReadOrWriteOnly( schema: OpenAPIV3_1.SchemaObject, readOrWriteOnly: 'readOnly' | 'writeOnly' diff --git a/helper/crosslab-typescript-addon/templates/client/requestValidation.ts.njk b/helper/crosslab-typescript-addon/templates/client/requestValidation.ts.njk index 16861f6a..e8f79986 100644 --- a/helper/crosslab-typescript-addon/templates/client/requestValidation.ts.njk +++ b/helper/crosslab-typescript-addon/templates/client/requestValidation.ts.njk @@ -69,21 +69,34 @@ export namespace {{ serviceName | formatName }}RequestValidation { if (parameters) { {%- for parameter in operation.parameters %} if ( - {{ "parameters['" + parameter.name + "'] && " if not parameter.required -}} - !{{ basicValidation }}.validate{{ parameter.name | formatName -}} - (parameters["{{ parameter.name }}"]) + !{{ basicValidation }}.validate{{ parameter.name | formatName -}}Request(parameters["{{ parameter.name }}"]) + {{- "\n\t\t\t&& parameters['" + parameter.name + "'] !== undefined" if not parameter.required }} ) { - (validate{{ cap_name }}Input as any).errors = ({{ basicValidation }}.validate{{ parameter.name | formatName }} as any).errors + (validate{{ cap_name }}Input as any).errors = ({{ basicValidation }}.validate{{ parameter.name | formatName }}Request as any).errors return false } {%- endfor %} + } else { + {%- if operation.parameters | selectattr("required") | length > 0 %} + return false + {%- else %} + if (parameters !== undefined) { + return false + } + {%- endif %} } {% endif -%} {% if operation.requestBody -%} - if ({{ "body && " if not operation.requestBody.required -}}!{{ basicValidation }}.validate{{ cap_name }}Body(body)) { - (validate{{ cap_name }}Input as any).errors = ({{ basicValidation }}.validate{{ cap_name }}Body as any).errors + {% if not operation.requestBody.required -%} + if (body === undefined) { + return true + } + + {% endif -%} + if (!{{ basicValidation }}.validate{{ cap_name }}BodyRequest(body)) { + (validate{{ cap_name }}Input as any).errors = ({{ basicValidation }}.validate{{ cap_name }}BodyRequest as any).errors return false } @@ -99,25 +112,36 @@ export namespace {{ serviceName | formatName }}RequestValidation { if (response.status < 100 || response.status >= 600) return false {% for response in operation.responses -%} + {%- if response.status | endsWith("XX") %} + if (response.status >= {{ (response.status | replace("X","0") | int) }} && response.status < {{ (response.status | replace("X","0") | int) + 100 }} ) { + {%- else %} if (response.status === {{ response.status }}) { + {%- endif %} {% if response.headers -%} if (response.headers) { {%- for header in response.headers %} if ( - {{ "response.headers['" + header.name + "'] && " if not header.required -}} - !{{ basicValidation }}.validate{{ cap_name }}{{ header.name | formatName -}} - (response.headers["{{ header.name }}"]) + !{{ basicValidation }}.validate{{ cap_name }}{{ header.name }}Response(response.headers["{{ header.name }}"]) + {{ "\n\t\t\t\t&& response.headers['" + header.name + "'] !== undefined " if not header.required -}} ) { - (validate{{ cap_name }}Output as any).errors = ({{ basicValidation }}.validate{{ cap_name }}{{ header.name | formatName }} as any).errors + (validate{{ cap_name }}Output as any).errors = ({{ basicValidation }}.validate{{ cap_name }}{{ header.name }}Response as any).errors return false } {%- endfor %} + } else { + {%- if response.headers | selectattr("required") | length > 0 %} + return false + {%- else %} + if (response.headers !== undefined) { + return false + } + {%- endif %} } {% endif -%} {% if response.schema -%} - if (!{{ basicValidation }}.validate{{ cap_name }}Response{{ response.status }}(response.body)) { - (validate{{ cap_name }}Output as any).errors = ({{ basicValidation }}.validate{{ cap_name }}Response{{ response.status }} as any).errors + if (!{{ basicValidation }}.validate{{ cap_name }}Response{{ response.status }}Response(response.body)) { + (validate{{ cap_name }}Output as any).errors = ({{ basicValidation }}.validate{{ cap_name }}Response{{ response.status }}Response as any).errors return false } diff --git a/helper/crosslab-typescript-addon/templates/service/requestValidation.ts.njk b/helper/crosslab-typescript-addon/templates/service/requestValidation.ts.njk index 3c91b6c1..26e7f8f0 100644 --- a/helper/crosslab-typescript-addon/templates/service/requestValidation.ts.njk +++ b/helper/crosslab-typescript-addon/templates/service/requestValidation.ts.njk @@ -41,9 +41,7 @@ import { {{ signatureDependencies | unique | join(",\n\t") }} } from "./signatures" -import { - {{ validationDependencies | unique | join(",\n\t") }} -} from "./basicValidation" +import * as basicValidation from "./basicValidation" {%- for operation in operations %} @@ -59,10 +57,10 @@ export function validate{{ operation.name | cap }}Input( if (parameters) { {%- for parameter in operation.parameters %} if ( - !validate{{ parameter.name | formatName -}}(parameters["{{ parameter.name }}"]) + !basicValidation.validate{{ parameter.name | formatName -}}Request(parameters["{{ parameter.name }}"]) {{- "\n\t\t\t&& parameters['" + parameter.name + "'] !== undefined" if not parameter.required }} ) { - (validate{{ operation.name | cap }}Input as any).errors = (validate{{ parameter.name | formatName }} as any).errors + (validate{{ operation.name | cap }}Input as any).errors = (basicValidation.validate{{ parameter.name | formatName }}Request as any).errors return false } {%- endfor %} @@ -85,8 +83,8 @@ export function validate{{ operation.name | cap }}Input( } {% endif -%} - if (!validate{{ operation.name | cap }}RequestBody(body)) { - (validate{{ operation.name | cap }}Input as any).errors = (validate{{ operation.name | cap }}RequestBody as any).errors + if (!basicValidation.validate{{ operation.name | cap }}RequestBodyRequest(body)) { + (validate{{ operation.name | cap }}Input as any).errors = (basicValidation.validate{{ operation.name | cap }}RequestBodyRequest as any).errors return false } @@ -111,10 +109,10 @@ export function validate{{ operation.name | cap }}Output(response: ResponseData) if (response.headers) { {%- for header in response.headers %} if ( - !validate{{ operation.name | cap }}Header{{ header.name }}(response.headers["{{ header.name }}"]) + !basicValidation.validate{{ operation.name | cap }}Header{{ header.name }}Response(response.headers["{{ header.name }}"]) {{ "\n\t\t\t\t&& response.headers['" + header.name + "'] !== undefined " if not header.required -}} ) { - (validate{{ operation.name | cap }}Output as any).errors = (validate{{ operation.name | cap }}Header{{ header.name }} as any).errors + (validate{{ operation.name | cap }}Output as any).errors = (basicValidation.validate{{ operation.name | cap }}Header{{ header.name }}Response as any).errors return false } {%- endfor %} @@ -130,8 +128,8 @@ export function validate{{ operation.name | cap }}Output(response: ResponseData) {% endif -%} {% if response.schema -%} - if (!validate{{ operation.name | cap }}Response{{ response.status }}(response.body)) { - (validate{{ operation.name | cap }}Output as any).errors = (validate{{ operation.name | cap }}Response{{ response.status }} as any).errors + if (!basicValidation.validate{{ operation.name | cap }}Response{{ response.status }}Response(response.body)) { + (validate{{ operation.name | cap }}Output as any).errors = (basicValidation.validate{{ operation.name | cap }}Response{{ response.status }}Response as any).errors return false } diff --git a/integration-test/package-lock.json b/integration-test/package-lock.json index fd70d236..fc9ffabc 100644 --- a/integration-test/package-lock.json +++ b/integration-test/package-lock.json @@ -134,8 +134,8 @@ "ldapts": "^4.1.0", "mysql": "^2.18.1", "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "winston": "^3.8.1", "ws": "^8.8.0" }, @@ -190,10 +190,14 @@ }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "eslint": "^8.34.0", + "mocha": "^10.2.0", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "typescript": "^4.9.4" } }, @@ -209,28 +213,45 @@ "jose": "^4.10.0", "mysql": "^2.18.1", "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", + "queue": "^6.0.2", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "ws": "^8.8.0" }, "bin": { "crosslab-device-service": "app/index.js" }, "devDependencies": { + "@babel/register": "^7.21.0", "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", "@trivago/prettier-plugin-sort-imports": "^4.0.0", "@types/body-parser": "^1.19.2", "@types/express": "^4.17.13", + "@types/mocha": "^10.0.1", "@types/node": "^18.0.3", "@types/node-fetch": "^2.6.1", + "@types/rewire": "^2.5.28", + "@types/seedrandom": "^3.0.5", + "@types/sinon": "^10.0.13", + "@types/supertest": "^2.0.12", "@types/ws": "^8.5.3", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "env-cmd": "^10.1.0", "eslint": "^8.34.0", + "json-schema-faker": "^0.5.0-rcv.46", + "mocha": "^10.2.0", "nodemon": "^2.0.19", + "npm-run-all": "^4.1.5", + "nyc": "^15.1.0", "prettier": "^2.7.1", + "randexp": "^0.5.3", + "rewire": "^6.0.0", + "seedrandom": "^3.0.5", + "sinon": "^15.0.2", + "supertest": "^6.3.3", + "ts-mocha": "^10.0.0", "ts-node": "^10.9.1", "typescript": "^4.7.4" } @@ -247,8 +268,8 @@ "express-winston": "^4.2.0", "jose": "^4.10.0", "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "winston": "^3.8.2" }, "bin": { @@ -285,8 +306,8 @@ "jose": "^4.10.0", "mysql": "^2.18.1", "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6" + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15" }, "bin": { "crosslab-federation-service": "app/index.js" diff --git a/services/auth/package-lock.json b/services/auth/package-lock.json index 8b0a62a3..8f9e6e40 100644 --- a/services/auth/package-lock.json +++ b/services/auth/package-lock.json @@ -17,8 +17,8 @@ "ldapts": "^4.1.0", "mysql": "^2.18.1", "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "winston": "^3.8.1", "ws": "^8.8.0" }, @@ -120,6 +120,7 @@ "ajv-formats": "^2.1.1", "commander": "^9.4.1", "deterministic-json-schema-faker": "^0.5.0-rcv.46", + "json-schema-merge-allof": "^0.8.1", "json-schema-to-typescript": "^10.1.5", "nunjucks": "^3.2.3", "prettier": "^2.6.2", @@ -151,20 +152,24 @@ }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "eslint": "^8.34.0", + "mocha": "^10.2.0", + "sqlite3": "^5.0.8", + "typeorm": "^0.3.15", "typescript": "^4.9.4" } }, "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { @@ -216,9 +221,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dev": true, "dependencies": { "@babel/highlight": "^7.18.6" @@ -228,30 +233,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", - "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", + "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.20.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", - "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.20.11", - "@babel/helpers": "^7.20.7", - "@babel/parser": "^7.20.7", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", + "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", + "@babel/helper-compilation-targets": "^7.21.4", + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.4", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.12", - "@babel/types": "^7.20.7", + "@babel/traverse": "^7.21.4", + "@babel/types": "^7.21.4", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -267,41 +272,28 @@ } }, "node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", + "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", "dev": true, "dependencies": { - "@babel/types": "^7.20.7", + "@babel/types": "^7.21.4", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", + "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", + "@babel/compat-data": "^7.21.4", + "@babel/helper-validator-option": "^7.21.0", "browserslist": "^4.21.3", "lru-cache": "^5.1.1", "semver": "^6.3.0" @@ -323,13 +315,13 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" @@ -348,21 +340,21 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", + "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.21.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", + "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", @@ -371,8 +363,8 @@ "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.2", + "@babel/types": "^7.21.2" }, "engines": { "node": ">=6.9.0" @@ -421,23 +413,23 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", + "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", - "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", + "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", "dev": true, "dependencies": { "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.13", - "@babel/types": "^7.20.7" + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" @@ -458,9 +450,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -470,9 +462,9 @@ } }, "node_modules/@babel/register": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.9.tgz", - "integrity": "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.21.0.tgz", + "integrity": "sha512-9nKsPmYDi5DidAqJaQooxIhsLJiNMkGr8ypQ8Uic7cIox7UCDsM7HuUGxdGT7mSDTYbqzIdsOWzfBton/YJrMw==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", @@ -503,19 +495,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", + "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", + "@babel/code-frame": "^7.21.4", + "@babel/generator": "^7.21.4", "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", + "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", + "@babel/parser": "^7.21.4", + "@babel/types": "^7.21.4", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -524,9 +516,9 @@ } }, "node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -593,15 +585,39 @@ "kuler": "^2.0.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -683,6 +699,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -790,6 +815,15 @@ "node": ">=8" } }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -800,13 +834,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" @@ -831,21 +866,27 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "devOptional": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", @@ -905,9 +946,9 @@ } }, "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -981,9 +1022,9 @@ } }, "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "optional": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1016,9 +1057,9 @@ } }, "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "dependencies": { "type-detect": "4.0.8" @@ -1033,10 +1074,19 @@ "@sinonjs/commons": "^2.0.0" } }, + "node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, "node_modules/@sinonjs/samsam": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", - "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", "dev": true, "dependencies": { "@sinonjs/commons": "^2.0.0", @@ -1044,6 +1094,15 @@ "type-detect": "^4.0.8" } }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, "node_modules/@sinonjs/text-encoding": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", @@ -1065,52 +1124,26 @@ } }, "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.0.0.tgz", - "integrity": "sha512-Tyuk5ZY4a0e2MNFLdluQO9F6d1awFQYXVVujEPFfvKPPXz8DADNHzz73NMhwCSXGSuGGZcA/rKOyZBrxVNMxaA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.1.1.tgz", + "integrity": "sha512-dQ2r2uzNr1x6pJsuh/8x0IRA3CBUB+pWEW3J/7N98axqt7SQSm+2fy0FLNXvXGg77xEDC7KHxJlHfLYyi7PDcw==", "dev": true, "dependencies": { - "@babel/core": "7.17.8", "@babel/generator": "7.17.7", - "@babel/parser": "7.18.9", + "@babel/parser": "^7.20.5", "@babel/traverse": "7.17.3", "@babel/types": "7.17.0", "javascript-natural-sort": "0.7.1", - "lodash": "4.17.21" + "lodash": "^4.17.21" }, "peerDependencies": { "@vue/compiler-sfc": "3.x", "prettier": "2.x" - } - }, - "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/core": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", - "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.7", - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helpers": "^7.17.8", - "@babel/parser": "^7.17.8", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + } } }, "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/generator": { @@ -1127,18 +1160,6 @@ "node": ">=6.9.0" } }, - "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", - "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/traverse": { "version": "7.17.3", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", @@ -1258,14 +1279,15 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.33", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", - "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "version": "4.17.34", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", + "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", "dev": true, "dependencies": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*" + "@types/range-parser": "*", + "@types/send": "*" } }, "node_modules/@types/json-schema": { @@ -1291,9 +1313,9 @@ "optional": true }, "node_modules/@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, "node_modules/@types/mocha": { @@ -1303,14 +1325,14 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==" + "version": "18.16.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.1.tgz", + "integrity": "sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==" }, "node_modules/@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.3.tgz", + "integrity": "sha512-ETTL1mOEdq/sxUtgtOhKjyB2Irra4cjxksvcMUR5Zr4n+PxVhsCD9WS46oPbHL3et9Zde7CNRr+WUNlcHvsX+w==", "dev": true, "dependencies": { "@types/node": "*", @@ -1336,9 +1358,9 @@ "dev": true }, "node_modules/@types/seedrandom": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.4.tgz", - "integrity": "sha512-/rWdxeiuZenlawrHU+XV6ZHMTKOqrC2hMfeDfLTIWJhDZP5aVqXRysduYHBbhD7CeJO6FJr/D2uBVXB7GT6v7w==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-kopEpYpFQvQdYsZkZVwht/0THHmTFFYXDaqV/lM45eweJ8kcGVDgZHs0RVTolSq55UPZNmjhKc9r7UvLu/mQQg==", "dev": true }, "node_modules/@types/semver": { @@ -1347,10 +1369,20 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "node_modules/@types/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", "dev": true, "dependencies": { "@types/mime": "*", @@ -1358,9 +1390,9 @@ } }, "node_modules/@types/sinon": { - "version": "10.0.13", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", - "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==", + "version": "10.0.14", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.14.tgz", + "integrity": "sha512-mn72up6cjaMyMuaPaa/AwKf6WtsSRysQC7wxFkCm1XcOKXPM1z+5Y4H5wjIVBz4gdAkjvZxVVfjA6ba1nHr5WQ==", "dev": true, "dependencies": { "@types/sinonjs__fake-timers": "*" @@ -1373,9 +1405,9 @@ "dev": true }, "node_modules/@types/superagent": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.16.tgz", - "integrity": "sha512-tLfnlJf6A5mB6ddqF159GqcDizfzbMUB1/DeT59/wBNqzRTNNKsaw79A/1TZ84X+f/EwWH8FeuSkjlCLyqS/zQ==", + "version": "4.1.17", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.17.tgz", + "integrity": "sha512-FFK/rRjNy24U6J1BvQkaNWu2ohOIF/kxRQXRsbT141YQODcOcZjzlcc4DGdI2SkTa0rhmF+X14zu6ICjCGIg+w==", "dev": true, "dependencies": { "@types/cookiejar": "*", @@ -1397,9 +1429,9 @@ "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" }, "node_modules/@types/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==" + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==" }, "node_modules/@types/ws": { "version": "8.5.4", @@ -1411,19 +1443,19 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", - "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz", + "integrity": "sha512-AVi0uazY5quFB9hlp2Xv+ogpfpk77xzsgsIEWyVS7uK/c7MZ5tw7ZPbapa0SbfkqE0fsAMkz5UwtgMLVk2BQAg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/type-utils": "5.52.0", - "@typescript-eslint/utils": "5.52.0", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/type-utils": "5.59.1", + "@typescript-eslint/utils": "5.59.1", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, @@ -1457,9 +1489,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1478,14 +1510,14 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", - "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.1.tgz", + "integrity": "sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/typescript-estree": "5.59.1", "debug": "^4.3.4" }, "engines": { @@ -1505,13 +1537,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", - "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.1.tgz", + "integrity": "sha512-mau0waO5frJctPuAzcxiNWqJR5Z8V0190FTSqRw1Q4Euop6+zTwHAf8YIXNwDOT29tyUDrQ65jSg9aTU/H0omA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0" + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1522,13 +1554,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", - "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.1.tgz", + "integrity": "sha512-ZMWQ+Oh82jWqWzvM3xU+9y5U7MEMVv6GLioM3R5NJk6uvP47kZ7YvlgSHJ7ERD6bOY7Q4uxWm25c76HKEwIjZw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.52.0", - "@typescript-eslint/utils": "5.52.0", + "@typescript-eslint/typescript-estree": "5.59.1", + "@typescript-eslint/utils": "5.59.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1549,9 +1581,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.1.tgz", + "integrity": "sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1562,13 +1594,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", - "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz", + "integrity": "sha512-lYLBBOCsFltFy7XVqzX0Ju+Lh3WPIAWxYpmH/Q7ZoqzbscLiCW00LeYCdsUnnfnj29/s1WovXKh2gwCoinHNGA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1601,9 +1633,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1622,18 +1654,18 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", - "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.1.tgz", + "integrity": "sha512-MkTe7FE+K1/GxZkP5gRj3rCztg45bEhsd8HYjczBuYm+qFHP5vtZmjx3B0yUCDotceQ4sHgTyz60Ycl225njmA==", "dev": true, "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/typescript-estree": "5.59.1", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "engines": { @@ -1660,9 +1692,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -1681,12 +1713,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz", + "integrity": "sha512-6waEYwBTCWryx0VJmP7JaM4FpipLsFl9CvYf2foAE8Qh/Y0s+bxWysciwOs0LTBED4JCaNxTZ5rGadB14M6dwA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/types": "5.59.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1697,101 +1729,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@vue/compiler-core": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", - "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "source-map": "^0.6.1" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", - "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/compiler-core": "3.2.47", - "@vue/shared": "3.2.47" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", - "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.47", - "@vue/compiler-dom": "3.2.47", - "@vue/compiler-ssr": "3.2.47", - "@vue/reactivity-transform": "3.2.47", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7", - "postcss": "^8.1.10", - "source-map": "^0.6.1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "peer": true, - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", - "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/compiler-dom": "3.2.47", - "@vue/shared": "3.2.47" - } - }, - "node_modules/@vue/reactivity-transform": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", - "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.47", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7" - } - }, - "node_modules/@vue/reactivity-transform/node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "peer": true, - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, - "node_modules/@vue/shared": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", - "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==", - "dev": true, - "peer": true - }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -1810,10 +1747,10 @@ } }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "devOptional": true, "bin": { "acorn": "bin/acorn" }, @@ -1851,28 +1788,19 @@ } }, "node_modules/agentkeepalive": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", - "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", "optional": true, "dependencies": { "debug": "^4.1.0", - "depd": "^1.1.2", + "depd": "^2.0.0", "humanize-ms": "^1.2.1" }, "engines": { "node": ">= 8.0.0" } }, - "node_modules/agentkeepalive/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "optional": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -2022,9 +1950,9 @@ } }, "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2049,6 +1977,19 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -2165,12 +2106,12 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -2178,7 +2119,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -2421,9 +2362,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001451", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz", - "integrity": "sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w==", + "version": "1.0.30001481", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", + "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==", "dev": true, "funding": [ { @@ -2433,6 +2374,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -2477,6 +2422,18 @@ "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -2662,6 +2619,15 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -2753,18 +2719,6 @@ "node": ">= 8" } }, - "node_modules/date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2897,15 +2851,6 @@ "node": ">=8" } }, - "node_modules/dir-glob/node_modules/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, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2941,9 +2886,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.295", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz", - "integrity": "sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==", + "version": "1.4.374", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.374.tgz", + "integrity": "sha512-dNP9tQNTrjgVlSXMqGaj0BdrCS+9pcUvy5/emB6x8kh0YwCoDZ0Z4ce1+7aod+KhybHUd5o5LgKrc5al4kVmzQ==", "dev": true }, "node_modules/emoji-regex": { @@ -3013,15 +2958,6 @@ "node": ">=8.0.0" } }, - "node_modules/env-cmd/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -3047,18 +2983,18 @@ } }, "node_modules/es-abstract": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", - "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", "dev": true, "dependencies": { + "array-buffer-byte-length": "^1.0.0", "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", @@ -3066,8 +3002,8 @@ "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.4", - "is-array-buffer": "^3.0.1", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", @@ -3075,11 +3011,12 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", + "object-inspect": "^1.12.3", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", "string.prototype.trimend": "^1.0.6", "string.prototype.trimstart": "^1.0.6", "typed-array-length": "^1.0.4", @@ -3153,12 +3090,15 @@ } }, "node_modules/eslint": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", - "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.1", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3168,11 +3108,10 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", @@ -3193,7 +3132,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -3222,39 +3160,39 @@ } }, "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^2.0.0" + "eslint-visitor-keys": "^1.1.0" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" } }, "node_modules/eslint-utils/node_modules/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==", + "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, "engines": { - "node": ">=10" + "node": ">=4" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ajv": { @@ -3341,9 +3279,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -3351,6 +3289,9 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/estraverse": { @@ -3362,18 +3303,6 @@ "node": ">=4.0" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/eslint/node_modules/globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", @@ -3441,14 +3370,14 @@ } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3457,18 +3386,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/espree/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -3483,9 +3400,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -3533,13 +3450,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "peer": true - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3598,6 +3508,29 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3611,6 +3544,20 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3632,6 +3579,18 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/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", @@ -3890,6 +3849,20 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -4003,14 +3976,14 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.1.1", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -4022,15 +3995,15 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/globals": { @@ -4090,9 +4063,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "devOptional": true }, "node_modules/grapheme-splitter": { @@ -4356,15 +4329,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/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, - "engines": { - "node": ">=4" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -4432,13 +4396,13 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz", - "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.0", "is-typed-array": "^1.1.10" }, "funding": { @@ -4504,9 +4468,9 @@ } }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", + "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -4924,17 +4888,17 @@ "dev": true }, "node_modules/jose": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.4.tgz", - "integrity": "sha512-94FdcR8felat4vaTJyL/WVdtlWLlsnLMZP8v+A0Vru18K3bQ22vn7TtpVh3JlgBFNIlYOUlGqwp/MjRPOnIyCQ==", + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.3.tgz", + "integrity": "sha512-YPM9Q+dmsna4CGWNn5+oHFsuXJdxvKAOVoNjpe2nje3odSoX5Xz4s71rP50vM8uUKJyQtMnEGPmbVCVR+G4W5g==", "funding": { "url": "https://github.com/sponsors/panva" } }, "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", "dev": true, "funding": { "type": "opencollective", @@ -5056,9 +5020,9 @@ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, "node_modules/ldapts": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/ldapts/-/ldapts-4.2.2.tgz", - "integrity": "sha512-UHe7BtEhPUFHZZ6XHnRvLHWQrftTap3PgGU0nOLtrFeigZvfpXSsqJ8C9uXNouDV+iDHqoWwplS0eHoDu/GIEQ==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/ldapts/-/ldapts-4.2.5.tgz", + "integrity": "sha512-4R+q+TGFBoXqERwWWvZPF/x1X4y5vdoHhaPWzs8gHXG6mIGJrrGanUWTb7+wZ9G8+razNQ1d8tHv94mFD+3jHQ==", "dependencies": { "@types/asn1": ">=0.2.0", "@types/node": ">=14", @@ -5607,48 +5571,25 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/mocha/node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "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" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "balanced-match": "^1.0.0" } }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/mocha/node_modules/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, - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/mocha/node_modules/has-flag": { @@ -5684,15 +5625,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -5799,6 +5731,15 @@ "path-to-regexp": "^1.7.0" } }, + "node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, "node_modules/nise/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -5922,9 +5863,9 @@ } }, "node_modules/node-gyp/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "optional": true, "dependencies": { "inherits": "^2.0.3", @@ -5936,9 +5877,9 @@ } }, "node_modules/node-gyp/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "optional": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5975,9 +5916,9 @@ "dev": true }, "node_modules/nodemon": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", - "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -6348,6 +6289,15 @@ "node": ">=8" } }, + "node_modules/nyc/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/nyc/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -6660,24 +6610,12 @@ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/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, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-type/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/picocolors": { @@ -6801,44 +6739,6 @@ "node": ">=4" } }, - "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -6849,9 +6749,9 @@ } }, "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -6999,9 +6899,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -7026,6 +6926,27 @@ "node": ">=4" } }, + "node_modules/read-pkg/node_modules/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, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -7063,14 +6984,14 @@ "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -7126,12 +7047,12 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.11.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -7143,12 +7064,12 @@ } }, "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "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, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/ret": { @@ -7231,6 +7152,18 @@ "node": ">=10.10.0" } }, + "node_modules/rewire/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/rewire/node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -7365,30 +7298,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/rewire/node_modules/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, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/rewire/node_modules/eslint-utils/node_modules/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, - "engines": { - "node": ">=4" - } - }, "node_modules/rewire/node_modules/eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", @@ -7421,6 +7330,18 @@ "node": ">=4" } }, + "node_modules/rewire/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/rewire/node_modules/globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", @@ -7473,9 +7394,9 @@ } }, "node_modules/rewire/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -7588,9 +7509,9 @@ } }, "node_modules/safe-stable-stringify": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", - "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", "engines": { "node": ">=10" } @@ -7600,11 +7521,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, "node_modules/seedrandom": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", @@ -7740,9 +7656,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", - "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7801,16 +7717,16 @@ } }, "node_modules/sinon": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.1.tgz", - "integrity": "sha512-PZXKc08f/wcA/BMRGBze2Wmw50CWPiAH3E21EOi4B49vJ616vW4DQh4fQrqsYox2aNR/N3kCqLuB0PwwOucQrg==", + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.4.tgz", + "integrity": "sha512-uzmfN6zx3GQaria1kwgWGeKiXSSbShBbue6Dcj0SI8fiCNFbiUDqKl57WFlY5lyhxZVUKmXvzgG2pilRQCBwWg==", "dev": true, "dependencies": { - "@sinonjs/commons": "^2.0.0", - "@sinonjs/fake-timers": "10.0.2", - "@sinonjs/samsam": "^7.0.1", - "diff": "^5.0.0", - "nise": "^5.1.2", + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.4", "supports-color": "^7.2.0" }, "funding": { @@ -7818,6 +7734,15 @@ "url": "https://opencollective.com/sinon" } }, + "node_modules/sinon/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/sinon/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -7945,16 +7870,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -7965,14 +7880,6 @@ "source-map": "^0.6.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true, - "peer": true - }, "node_modules/spawn-wrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", @@ -8006,9 +7913,9 @@ } }, "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", @@ -8032,9 +7939,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", "dev": true }, "node_modules/sprintf-js": { @@ -8044,9 +7951,9 @@ "dev": true }, "node_modules/sqlite3": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.4.tgz", - "integrity": "sha512-i0UlWAzPlzX3B5XP2cYuhWQJsTtlMD6obOa1PgeEQ4DHEXUuyJkgv50I3isqZAP5oFc2T8OFvakmDh2W6I+YpA==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz", + "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", "hasInstallScript": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", @@ -8149,6 +8056,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/string.prototype.trimend": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", @@ -8269,9 +8193,9 @@ } }, "node_modules/superagent/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -8359,9 +8283,9 @@ } }, "node_modules/tar/node_modules/minipass": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", - "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", "engines": { "node": ">=8" } @@ -8597,18 +8521,6 @@ } } }, - "node_modules/ts-node/node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "devOptional": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/ts-node/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -8619,14 +8531,14 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", "dev": true, "optional": true, "dependencies": { "@types/json5": "^0.0.29", - "json5": "^1.0.1", + "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } @@ -8655,9 +8567,10 @@ } }, "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true }, "node_modules/tsutils": { "version": "3.21.0", @@ -8674,12 +8587,6 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -8746,26 +8653,23 @@ } }, "node_modules/typeorm": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", - "integrity": "sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==", + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.15.tgz", + "integrity": "sha512-R4JSw8QjDP1W+ypeRz/XrCXIqubrLSnNAzJAp9EQSQIPHTv+YmUHZis8g08lOwFpuhqL9m8jkPSz8GWEKlU/ow==", "dependencies": { "@sqltools/formatter": "^1.2.5", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "chalk": "^4.1.2", "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", "debug": "^4.3.4", "dotenv": "^16.0.3", "glob": "^8.1.0", - "js-yaml": "^4.1.0", "mkdirp": "^2.1.3", "reflect-metadata": "^0.1.13", "sha.js": "^2.4.11", "tslib": "^2.5.0", "uuid": "^9.0.0", - "xml2js": "^0.4.23", "yargs": "^17.6.2" }, "bin": { @@ -8785,8 +8689,8 @@ "better-sqlite3": "^7.1.2 || ^8.0.0", "hdb-pool": "^0.1.6", "ioredis": "^5.0.4", - "mongodb": "^3.6.0", - "mssql": "^7.3.0", + "mongodb": "^5.2.0", + "mssql": "^9.1.1", "mysql2": "^2.2.5 || ^3.0.1", "oracledb": "^5.1.0", "pg": "^8.5.1", @@ -8866,11 +8770,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/typeorm/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, "node_modules/typeorm/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -8949,17 +8848,6 @@ "node": ">=8" } }, - "node_modules/typeorm/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/typeorm/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -8972,9 +8860,9 @@ } }, "node_modules/typeorm/node_modules/mkdirp": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.3.tgz", - "integrity": "sha512-sjAkg21peAG9HS+Dkx7hlG9Ztx7HLeKnvB3NQRcu/mltCVmvkF0pisbiTSfDVYTT86XEfZrTUosLdZLStquZUw==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", "bin": { "mkdirp": "dist/cjs/src/bin.js" }, @@ -8996,10 +8884,15 @@ "node": ">=8" } }, + "node_modules/typeorm/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, "node_modules/typeorm/node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -9082,9 +8975,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "dev": true, "funding": [ { @@ -9094,6 +8987,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { @@ -9101,7 +8998,7 @@ "picocolors": "^1.0.0" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -9212,9 +9109,9 @@ } }, "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, "node_modules/which-typed-array": { @@ -9280,9 +9177,9 @@ } }, "node_modules/winston-transport/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9293,9 +9190,9 @@ } }, "node_modules/winston/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9384,9 +9281,9 @@ } }, "node_modules/ws": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", - "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "engines": { "node": ">=10.0.0" }, @@ -9403,26 +9300,6 @@ } } }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/services/auth/package.json b/services/auth/package.json index 9294ed20..13c7ada2 100644 --- a/services/auth/package.json +++ b/services/auth/package.json @@ -43,14 +43,11 @@ "author": "Johannes Nau", "license": "UNLICENSED", "devDependencies": { - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "eslint": "^8.34.0", "@apidevtools/swagger-parser": "^10.1.0", "@babel/register": "^7.18.9", "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", + "@trivago/prettier-plugin-sort-imports": "^4.0.0", "@types/bcryptjs": "^2.4.2", "@types/body-parser": "^1.19.2", "@types/express": "^4.17.13", @@ -63,7 +60,10 @@ "@types/sinon": "^10.0.13", "@types/supertest": "^2.0.12", "@types/ws": "^8.5.3", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", "env-cmd": "^10.1.0", + "eslint": "^8.34.0", "json-schema-faker": "^0.5.0-rcv.46", "mocha": "^10.2.0", "mocha-suppress-logs": "^0.3.1", @@ -92,8 +92,8 @@ "ldapts": "^4.1.0", "mysql": "^2.18.1", "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "winston": "^3.8.1", "ws": "^8.8.0" } diff --git a/services/common/package-lock.json b/services/common/package-lock.json index 4ae0d718..c1eb6de9 100644 --- a/services/common/package-lock.json +++ b/services/common/package-lock.json @@ -13,33 +13,19 @@ "@trivago/prettier-plugin-sort-imports": "^4.0.0", "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", - "@types/sinon": "^10.0.13", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "eslint": "^8.34.0", "mocha": "^10.2.0", - "sinon": "^15.0.1", - "typeorm": "^0.3.6", + "sqlite3": "^5.0.8", + "typeorm": "^0.3.15", "typescript": "^4.9.4" } }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", + "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", "dev": true, "dependencies": { "@babel/highlight": "^7.18.6" @@ -48,45 +34,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", - "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", - "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.7", - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helpers": "^7.17.8", - "@babel/parser": "^7.17.8", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, "node_modules/@babel/generator": { "version": "7.17.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", @@ -101,25 +48,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, "node_modules/@babel/helper-environment-visitor": { "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", @@ -130,22 +58,22 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", + "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.20.7", + "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -169,155 +97,9 @@ } }, "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -341,9 +123,9 @@ } }, "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -372,104 +154,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", - "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.13", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", @@ -485,9 +169,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", - "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", + "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -510,22 +194,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/template/node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", + "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", @@ -570,15 +242,39 @@ "node": ">=6.9.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -608,6 +304,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true, + "optional": true + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -641,51 +353,24 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" } }, "node_modules/@nodelib/fs.scandir": { @@ -723,64 +408,69 @@ "node": ">= 8" } }, - "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", "dev": true, + "optional": true, "dependencies": { - "@sinonjs/commons": "^2.0.0" + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" } }, - "node_modules/@sinonjs/samsam": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-7.0.1.tgz", - "integrity": "sha512-zsAk2Jkiq89mhZovB2LLOdTCxJF4hqqTToGP0ASWlhp4I1hqOjcfmZGafXntCN7MDC6yySH0mFHrYtHceOeLmw==", + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", "dev": true, + "optional": true, "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, "node_modules/@sqltools/formatter": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==", "dev": true }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.0.0.tgz", - "integrity": "sha512-Tyuk5ZY4a0e2MNFLdluQO9F6d1awFQYXVVujEPFfvKPPXz8DADNHzz73NMhwCSXGSuGGZcA/rKOyZBrxVNMxaA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.1.1.tgz", + "integrity": "sha512-dQ2r2uzNr1x6pJsuh/8x0IRA3CBUB+pWEW3J/7N98axqt7SQSm+2fy0FLNXvXGg77xEDC7KHxJlHfLYyi7PDcw==", "dev": true, "dependencies": { - "@babel/core": "7.17.8", "@babel/generator": "7.17.7", - "@babel/parser": "7.18.9", + "@babel/parser": "^7.20.5", "@babel/traverse": "7.17.3", "@babel/types": "7.17.0", "javascript-natural-sort": "0.7.1", - "lodash": "4.17.21" + "lodash": "^4.17.21" }, "peerDependencies": { "@vue/compiler-sfc": "3.x", "prettier": "2.x" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + } } }, "node_modules/@types/json-schema": { @@ -796,9 +486,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "version": "18.16.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.1.tgz", + "integrity": "sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==", "dev": true }, "node_modules/@types/semver": { @@ -807,35 +497,20 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, - "node_modules/@types/sinon": { - "version": "10.0.13", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", - "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==", - "dev": true, - "dependencies": { - "@types/sinonjs__fake-timers": "*" - } - }, - "node_modules/@types/sinonjs__fake-timers": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", - "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", - "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz", + "integrity": "sha512-AVi0uazY5quFB9hlp2Xv+ogpfpk77xzsgsIEWyVS7uK/c7MZ5tw7ZPbapa0SbfkqE0fsAMkz5UwtgMLVk2BQAg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/type-utils": "5.52.0", - "@typescript-eslint/utils": "5.52.0", + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/type-utils": "5.59.1", + "@typescript-eslint/utils": "5.59.1", "debug": "^4.3.4", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, @@ -856,48 +531,15 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/parser": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", - "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.1.tgz", + "integrity": "sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/typescript-estree": "5.59.1", "debug": "^4.3.4" }, "engines": { @@ -917,13 +559,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", - "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.1.tgz", + "integrity": "sha512-mau0waO5frJctPuAzcxiNWqJR5Z8V0190FTSqRw1Q4Euop6+zTwHAf8YIXNwDOT29tyUDrQ65jSg9aTU/H0omA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0" + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -934,13 +576,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", - "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.1.tgz", + "integrity": "sha512-ZMWQ+Oh82jWqWzvM3xU+9y5U7MEMVv6GLioM3R5NJk6uvP47kZ7YvlgSHJ7ERD6bOY7Q4uxWm25c76HKEwIjZw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.52.0", - "@typescript-eslint/utils": "5.52.0", + "@typescript-eslint/typescript-estree": "5.59.1", + "@typescript-eslint/utils": "5.59.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -961,9 +603,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.1.tgz", + "integrity": "sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -974,13 +616,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", - "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz", + "integrity": "sha512-lYLBBOCsFltFy7XVqzX0Ju+Lh3WPIAWxYpmH/Q7ZoqzbscLiCW00LeYCdsUnnfnj29/s1WovXKh2gwCoinHNGA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/visitor-keys": "5.59.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1000,52 +642,19 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", - "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.1.tgz", + "integrity": "sha512-MkTe7FE+K1/GxZkP5gRj3rCztg45bEhsd8HYjczBuYm+qFHP5vtZmjx3B0yUCDotceQ4sHgTyz60Ycl225njmA==", "dev": true, "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/scope-manager": "5.59.1", + "@typescript-eslint/types": "5.59.1", + "@typescript-eslint/typescript-estree": "5.59.1", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "engines": { @@ -1059,46 +668,13 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "version": "5.59.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz", + "integrity": "sha512-6waEYwBTCWryx0VJmP7JaM4FpipLsFl9CvYf2foAE8Qh/Y0s+bxWysciwOs0LTBED4JCaNxTZ5rGadB14M6dwA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/types": "5.59.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1109,120 +685,72 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@vue/compiler-core": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", - "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "source-map": "^0.6.1" - } + "node_modules/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 }, - "node_modules/@vue/compiler-core/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true, - "peer": true, + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/@vue/compiler-dom": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", - "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", + "node_modules/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, - "peer": true, - "dependencies": { - "@vue/compiler-core": "3.2.47", - "@vue/shared": "3.2.47" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@vue/compiler-sfc": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", - "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, - "peer": true, "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.47", - "@vue/compiler-dom": "3.2.47", - "@vue/compiler-ssr": "3.2.47", - "@vue/reactivity-transform": "3.2.47", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7", - "postcss": "^8.1.10", - "source-map": "^0.6.1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/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, - "peer": true, + "debug": "4" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 6.0.0" } }, - "node_modules/@vue/compiler-ssr": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", - "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", + "node_modules/agentkeepalive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", "dev": true, - "peer": true, + "optional": true, "dependencies": { - "@vue/compiler-dom": "3.2.47", - "@vue/shared": "3.2.47" + "debug": "^4.1.0", + "depd": "^2.0.0", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" } }, - "node_modules/@vue/reactivity-transform": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", - "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, - "peer": true, + "optional": true, "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.47", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7" - } - }, - "node_modules/@vue/shared": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", - "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==", - "dev": true, - "peer": true - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/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, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node": ">=8" } }, "node_modules/ajv": { @@ -1299,6 +827,25 @@ "node": ">= 6.0.0" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1377,34 +924,6 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -1429,6 +948,36 @@ "ieee754": "^1.2.1" } }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1450,22 +999,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001452", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz", - "integrity": "sha512-Lkp0vFjMkBB3GTpLR8zk4NwW5EdRdnitwYJHDOOKIU85x4ckYCPQ+9WlVvSVClHxVReefkUMtWZH2l9KGlD51w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -1519,6 +1052,25 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/cli-highlight": { "version": "2.1.11", "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", @@ -1571,17 +1123,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/cli-highlight/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, "node_modules/cli-highlight/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1621,45 +1162,15 @@ "node": ">=8" } }, - "node_modules/cli-highlight/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cli-highlight/node_modules/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==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", + "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" } }, "node_modules/color-convert": { @@ -1677,16 +1188,25 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "dev": true }, "node_modules/cross-spawn": { @@ -1703,19 +1223,6 @@ "node": ">= 8" } }, - "node_modules/date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", - "dev": true, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1751,6 +1258,31 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -1793,18 +1325,39 @@ "node": ">=12" } }, - "node_modules/electron-to-chromium": { - "version": "1.4.295", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz", - "integrity": "sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==", - "dev": true - }, "node_modules/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==", "dev": true }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "optional": true + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1824,12 +1377,15 @@ } }, "node_modules/eslint": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", - "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.1", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -1839,11 +1395,10 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", @@ -1864,7 +1419,6 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -1892,40 +1446,16 @@ "node": ">=8.0.0" } }, - "node_modules/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, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/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, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ansi-styles": { @@ -1990,9 +1520,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -2000,6 +1530,9 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/estraverse": { @@ -2048,14 +1581,14 @@ } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2065,9 +1598,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -2115,13 +1648,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "peer": true - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -2254,6 +1780,18 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2274,13 +1812,24 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=10" } }, "node_modules/get-caller-file": { @@ -2293,15 +1842,15 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.1.1", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -2353,6 +1902,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "optional": true + }, "node_modules/grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", @@ -2368,6 +1924,12 @@ "node": ">=4" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -2386,6 +1948,64 @@ "node": "*" } }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true, + "optional": true + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/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==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -2440,6 +2060,23 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true, + "optional": true + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2456,6 +2093,13 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true, + "optional": true + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2498,6 +2142,13 @@ "node": ">=0.10.0" } }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true, + "optional": true + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2537,12 +2188,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2556,17 +2201,17 @@ "dev": true }, "node_modules/jose": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.4.tgz", - "integrity": "sha512-94FdcR8felat4vaTJyL/WVdtlWLlsnLMZP8v+A0Vru18K3bQ22vn7TtpVh3JlgBFNIlYOUlGqwp/MjRPOnIyCQ==", + "version": "4.14.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.3.tgz", + "integrity": "sha512-YPM9Q+dmsna4CGWNn5+oHFsuXJdxvKAOVoNjpe2nje3odSoX5Xz4s71rP50vM8uUKJyQtMnEGPmbVCVR+G4W5g==", "funding": { "url": "https://github.com/sponsors/panva" } }, "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", "dev": true, "funding": { "type": "opencollective", @@ -2615,24 +2260,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", - "dev": true - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2667,12 +2294,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2753,84 +2374,221 @@ "node": ">=8" } }, - "node_modules/log-symbols/node_modules/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==", + "node_modules/log-symbols/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/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, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", "dev": true, + "optional": true, "dependencies": { - "has-flag": "^4.0.0" + "minipass": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", "dev": true, + "optional": true, "dependencies": { - "yallist": "^3.0.2" + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" } }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, - "peer": true, + "optional": true, "dependencies": { - "sourcemap-codec": "^1.4.8" + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "dev": true, + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, "engines": { - "node": ">= 8" + "node": ">=8" } }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "dev": true, + "optional": true, "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "minipass": "^3.0.0" }, "engines": { - "node": ">=8.6" + "node": ">=8" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "minipass": "^3.0.0", + "yallist": "^4.0.0" }, "engines": { - "node": "*" + "node": ">= 8" } }, "node_modules/mkdirp": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.3.tgz", - "integrity": "sha512-sjAkg21peAG9HS+Dkx7hlG9Ztx7HLeKnvB3NQRcu/mltCVmvkF0pisbiTSfDVYTT86XEfZrTUosLdZLStquZUw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, "bin": { - "mkdirp": "dist/cjs/src/bin.js" + "mkdirp": "bin/cmd.js" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha": { @@ -2873,15 +2631,13 @@ "url": "https://opencollective.com/mochajs" } }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "balanced-match": "^1.0.0" } }, "node_modules/mocha/node_modules/escape-string-regexp": { @@ -2896,38 +2652,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "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" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/mocha/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2949,33 +2673,12 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/mocha/node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -2991,33 +2694,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -3036,11 +2712,10 @@ } }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "dev": true, - "peer": true, "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -3060,25 +2735,132 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, - "node_modules/nise": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", - "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0", - "@sinonjs/fake-timers": "^10.0.2", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "path-to-regexp": "^1.7.0" + "optional": true, + "engines": { + "node": ">= 0.6" } }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", "dev": true }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "dev": true, + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -3088,6 +2870,18 @@ "node": ">=0.10.0" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3153,6 +2947,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3213,15 +3023,6 @@ "node": ">=8" } }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "dependencies": { - "isarray": "0.0.1" - } - }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -3230,48 +3031,17 @@ "engines": { "node": ">=8" } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/prelude-ls": { @@ -3284,9 +3054,9 @@ } }, "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "peer": true, "bin": { @@ -3299,6 +3069,27 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true, + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -3337,6 +3128,20 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -3355,18 +3160,6 @@ "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", "dev": true }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3385,6 +3178,16 @@ "node": ">=4" } }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -3453,19 +3256,26 @@ } ] }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/serialize-javascript": { @@ -3477,6 +3287,12 @@ "randombytes": "^2.1.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, "node_modules/sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", @@ -3511,52 +3327,60 @@ "node": ">=8" } }, - "node_modules/sinon": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.0.1.tgz", - "integrity": "sha512-PZXKc08f/wcA/BMRGBze2Wmw50CWPiAH3E21EOi4B49vJ616vW4DQh4fQrqsYox2aNR/N3kCqLuB0PwwOucQrg==", + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0", - "@sinonjs/fake-timers": "10.0.2", - "@sinonjs/samsam": "^7.0.1", - "diff": "^5.0.0", - "nise": "^5.1.2", - "supports-color": "^7.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" + "engines": { + "node": ">=8" } }, - "node_modules/sinon/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, + "optional": true, "engines": { - "node": ">=8" + "node": ">= 6.0.0", + "npm": ">= 3.0.0" } }, - "node_modules/sinon/node_modules/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==", + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dev": true, + "optional": true, "dependencies": { - "has-flag": "^4.0.0" + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" }, "engines": { - "node": ">=8" + "node": ">= 10.13.0", + "npm": ">= 3.0.0" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", "dev": true, + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, "engines": { - "node": ">=8" + "node": ">= 10" } }, "node_modules/source-map": { @@ -3568,23 +3392,50 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "node_modules/sqlite3": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz", + "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", "dev": true, - "peer": true, + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "peer": true + "dependencies": { + "safe-buffer": "~5.2.0" + } }, "node_modules/string-width": { "version": "4.2.3", @@ -3636,6 +3487,32 @@ "node": ">=4" } }, + "node_modules/tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3684,6 +3561,12 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -3717,15 +3600,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -3739,9 +3613,9 @@ } }, "node_modules/typeorm": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", - "integrity": "sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==", + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.15.tgz", + "integrity": "sha512-R4JSw8QjDP1W+ypeRz/XrCXIqubrLSnNAzJAp9EQSQIPHTv+YmUHZis8g08lOwFpuhqL9m8jkPSz8GWEKlU/ow==", "dev": true, "dependencies": { "@sqltools/formatter": "^1.2.5", @@ -3749,17 +3623,14 @@ "buffer": "^6.0.3", "chalk": "^4.1.2", "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", "debug": "^4.3.4", "dotenv": "^16.0.3", "glob": "^8.1.0", - "js-yaml": "^4.1.0", "mkdirp": "^2.1.3", "reflect-metadata": "^0.1.13", "sha.js": "^2.4.11", "tslib": "^2.5.0", "uuid": "^9.0.0", - "xml2js": "^0.4.23", "yargs": "^17.6.2" }, "bin": { @@ -3779,8 +3650,8 @@ "better-sqlite3": "^7.1.2 || ^8.0.0", "hdb-pool": "^0.1.6", "ioredis": "^5.0.4", - "mongodb": "^3.6.0", - "mssql": "^7.3.0", + "mongodb": "^5.2.0", + "mssql": "^9.1.1", "mysql2": "^2.2.5 || ^3.0.1", "oracledb": "^5.1.0", "pg": "^8.5.1", @@ -3886,6 +3757,20 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/typeorm/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/typeorm/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3944,6 +3829,21 @@ "node": ">=10" } }, + "node_modules/typeorm/node_modules/mkdirp": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz", + "integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/typeorm/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3962,6 +3862,33 @@ "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", "dev": true }, + "node_modules/typeorm/node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/typeorm/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", @@ -3975,30 +3902,24 @@ "node": ">=4.2.0" } }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], + "optional": true, "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" } }, "node_modules/uri-js": { @@ -4010,6 +3931,12 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, "node_modules/uuid": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", @@ -4019,6 +3946,22 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4034,6 +3977,15 @@ "node": ">= 8" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -4105,28 +4057,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -4137,36 +4067,36 @@ } }, "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "dependencies": { - "cliui": "^8.0.1", + "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^4.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^20.2.2" }, "engines": { - "node": ">=12" + "node": ">=10" } }, "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "dev": true, "engines": { - "node": ">=12" + "node": ">=10" } }, "node_modules/yargs-unparser": { diff --git a/services/common/package.json b/services/common/package.json index 883be4e9..ef43c2ed 100644 --- a/services/common/package.json +++ b/services/common/package.json @@ -29,7 +29,8 @@ "@typescript-eslint/parser": "^5.51.0", "eslint": "^8.34.0", "mocha": "^10.2.0", - "typeorm": "^0.3.6", - "typescript": "^4.9.4" + "typescript": "^4.9.4", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15" } } diff --git a/services/device/package-lock.json b/services/device/package-lock.json index 0355796a..dabf1b42 100644 --- a/services/device/package-lock.json +++ b/services/device/package-lock.json @@ -16,8 +16,8 @@ "mysql": "^2.18.1", "node-fetch": "^2.6.7", "queue": "^6.0.2", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "ws": "^8.8.0" }, "bin": { @@ -155,7 +155,8 @@ "@typescript-eslint/parser": "^5.51.0", "eslint": "^8.34.0", "mocha": "^10.2.0", - "typeorm": "^0.3.6", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "typescript": "^4.9.4" } }, @@ -2876,18 +2877,6 @@ "node": ">= 8" } }, - "node_modules/date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -7702,11 +7691,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, "node_modules/seedrandom": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", @@ -8135,9 +8119,9 @@ "dev": true }, "node_modules/sqlite3": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.4.tgz", - "integrity": "sha512-i0UlWAzPlzX3B5XP2cYuhWQJsTtlMD6obOa1PgeEQ4DHEXUuyJkgv50I3isqZAP5oFc2T8OFvakmDh2W6I+YpA==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz", + "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", "hasInstallScript": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", @@ -8808,26 +8792,23 @@ } }, "node_modules/typeorm": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", - "integrity": "sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==", + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.15.tgz", + "integrity": "sha512-R4JSw8QjDP1W+ypeRz/XrCXIqubrLSnNAzJAp9EQSQIPHTv+YmUHZis8g08lOwFpuhqL9m8jkPSz8GWEKlU/ow==", "dependencies": { "@sqltools/formatter": "^1.2.5", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "chalk": "^4.1.2", "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", "debug": "^4.3.4", "dotenv": "^16.0.3", "glob": "^8.1.0", - "js-yaml": "^4.1.0", "mkdirp": "^2.1.3", "reflect-metadata": "^0.1.13", "sha.js": "^2.4.11", "tslib": "^2.5.0", "uuid": "^9.0.0", - "xml2js": "^0.4.23", "yargs": "^17.6.2" }, "bin": { @@ -8847,8 +8828,8 @@ "better-sqlite3": "^7.1.2 || ^8.0.0", "hdb-pool": "^0.1.6", "ioredis": "^5.0.4", - "mongodb": "^3.6.0", - "mssql": "^7.3.0", + "mongodb": "^5.2.0", + "mssql": "^9.1.1", "mysql2": "^2.2.5 || ^3.0.1", "oracledb": "^5.1.0", "pg": "^8.5.1", @@ -8928,11 +8909,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/typeorm/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, "node_modules/typeorm/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -8998,17 +8974,6 @@ "node": ">=8" } }, - "node_modules/typeorm/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/typeorm/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -9372,26 +9337,6 @@ } } }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/services/device/package.json b/services/device/package.json index 4b61162f..db40fec5 100644 --- a/services/device/package.json +++ b/services/device/package.json @@ -83,8 +83,8 @@ "mysql": "^2.18.1", "node-fetch": "^2.6.7", "queue": "^6.0.2", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "ws": "^8.8.0" } -} +} \ No newline at end of file diff --git a/services/device/src/config.ts b/services/device/src/config.ts index 2e365301..0c392ef8 100644 --- a/services/device/src/config.ts +++ b/services/device/src/config.ts @@ -45,6 +45,7 @@ export const config = initializeAppConfiguration() export const dataSourceConfig: DataSourceOptions = { type: 'sqlite', database: 'db/device.db', + synchronize: true, entities: [ DeviceOverviewModel, ConcreteDeviceModel, diff --git a/services/device/src/methods/signaling.ts b/services/device/src/methods/signaling.ts index 89b2d619..6098c33a 100644 --- a/services/device/src/methods/signaling.ts +++ b/services/device/src/methods/signaling.ts @@ -44,14 +44,14 @@ async function startSignaling(peerconnectionId: string) { where: { uuid: peerconnectionId, }, - relations: { - deviceA: { - config: true, - }, - deviceB: { - config: true, - }, - }, + // relations: { + // deviceA: { + // config: true, + // }, + // deviceB: { + // config: true, + // }, + // }, }) if (peerconnectionModel.status !== 'new') { diff --git a/services/experiment/package-lock.json b/services/experiment/package-lock.json index 69b2640d..e737559e 100644 --- a/services/experiment/package-lock.json +++ b/services/experiment/package-lock.json @@ -1,6127 +1,6080 @@ { - "name": "@crosslab/service-experiment", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@crosslab/service-experiment", - "license": "UNLICENSED", - "dependencies": { - "@cross-lab-project/api-client": "file:../../clients/api/js", - "@crosslab/service-common": "file:../common", - "ajv-formats": "^2.1.1", - "body-parser": "^1.20.0", - "express": "^4.18.1", - "express-winston": "^4.2.0", - "jose": "^4.10.0", - "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", - "winston": "^3.8.2" - }, - "bin": { - "crosslab-experiment-service": "app/index.js" - }, - "devDependencies": { - "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", - "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/body-parser": "^1.19.2", - "@types/express": "^4.17.13", - "@types/node": "^18.0.3", - "@types/node-fetch": "^2.6.1", - "@types/ws": "^8.5.3", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "env-cmd": "^10.1.0", - "eslint": "^8.34.0", - "nodemon": "^2.0.19", - "prettier": "^2.7.1", - "ts-node": "^10.9.1", - "typedoc": "^0.23.20", - "typescript": "^4.7.4" - } - }, - "../../clients/api/js": { - "license": "ISC", - "dependencies": { - "ajv-formats": "^2.1.1", - "cross-fetch": "^3.1.5" - }, - "devDependencies": { - "@cross-lab-project/codegen-typescript-addon": "file:../../../helper/crosslab-typescript-addon", - "@cross-lab-project/openapi-codegen": "file:../../../helper/openapi-codegeneration", - "@cross-lab-project/tsdoc-theme": "file:../../../helper/tsdoc-theme", - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/node": "^18.0.3", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "eslint": "^8.34.0", - "typedoc": "^0.23.20", - "typescript": "^4.7.4" - } - }, - "../../helper/crosslab-typescript-addon": { - "dev": true, - "license": "UNLICENSED", - "devDependencies": { - "@cross-lab-project/openapi-codegen": "file:../openapi-codegeneration", - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/node": "^17.0.35", - "@types/nunjucks": "^3.2.1", - "@types/prettier": "^2.6.3", - "@types/seedrandom": "^3.0.2", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "copyfiles": "^2.4.1", - "eslint": "^8.34.0", - "openapi-types": "^12.0.0", - "tsc-watch": "^5.0.3", - "typescript": "^4.6.4" - }, - "peerDependencies": { - "@apidevtools/swagger-parser": "^10.1.0", - "@cross-lab-project/openapi-codegen": "file:../openapi-codegeneration", - "ajv": "^8.11.0", - "ajv-formats": "^2.1.1", - "nunjucks": "^3.2.3", - "prettier": "^2.6.2" - } - }, - "../../helper/openapi-codegeneration": { - "dev": true, - "license": "UNLICENSED", - "dependencies": { - "@apidevtools/swagger-parser": "^10.1.0", - "ajv": "^8.11.0", - "ajv-formats": "^2.1.1", - "commander": "^9.4.1", - "deterministic-json-schema-faker": "^0.5.0-rcv.46", - "json-schema-to-typescript": "^10.1.5", - "nunjucks": "^3.2.3", - "prettier": "^2.6.2", - "quicktype-core": "^6.1.0", - "seedrandom": "^3.0.5", - "tiny-typed-emitter": "^2.1.0" - }, - "bin": { - "openapi-codegen": "lib/cjs/index.js" - }, - "devDependencies": { - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/node": "^17.0.45", - "@types/nunjucks": "^3.2.1", - "@types/prettier": "^2.6.3", - "@types/seedrandom": "^3.0.2", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "eslint": "^8.34.0", - "openapi-types": "^12.0.0", - "tsc-watch": "^5.0.3", - "typescript": "^4.6.4" - } - }, - "../common": { - "license": "UNLICENSED", - "dependencies": { - "jose": "^4.11.1" - }, - "devDependencies": { - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/node": "^18.11.18", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "eslint": "^8.34.0", - "typescript": "^4.9.4" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", - "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", - "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.7", - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helpers": "^7.17.8", - "@babel/parser": "^7.17.8", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", - "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", - "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.13", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", - "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@cross-lab-project/api-client": { - "resolved": "../../clients/api/js", - "link": true - }, - "node_modules/@cross-lab-project/codegen-typescript-addon": { - "resolved": "../../helper/crosslab-typescript-addon", - "link": true - }, - "node_modules/@cross-lab-project/openapi-codegen": { - "resolved": "../../helper/openapi-codegeneration", - "link": true - }, - "node_modules/@crosslab/service-common": { - "resolved": "../common", - "link": true - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/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 - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "optional": true - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "devOptional": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "devOptional": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", - "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", - "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/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==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/@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, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@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, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@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, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "optional": true, - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/@npmcli/fs/node_modules/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==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/fs/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "optional": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@sqltools/formatter": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", - "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "optional": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.0.0.tgz", - "integrity": "sha512-Tyuk5ZY4a0e2MNFLdluQO9F6d1awFQYXVVujEPFfvKPPXz8DADNHzz73NMhwCSXGSuGGZcA/rKOyZBrxVNMxaA==", - "dev": true, - "dependencies": { - "@babel/core": "7.17.8", - "@babel/generator": "7.17.7", - "@babel/parser": "7.18.9", - "@babel/traverse": "7.17.3", - "@babel/types": "7.17.0", - "javascript-natural-sort": "0.7.1", - "lodash": "4.17.21" - }, - "peerDependencies": { - "@vue/compiler-sfc": "3.x", - "prettier": "2.x" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "devOptional": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "devOptional": true - }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.33", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", - "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", - "devOptional": true - }, - "node_modules/@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, - "node_modules/@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==", - "dev": true - }, - "node_modules/@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==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "node_modules/@types/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", - "dev": true, - "dependencies": { - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@types/triple-beam": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz", - "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" - }, - "node_modules/@types/ws": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", - "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/type-utils": "5.52.0", - "@typescript-eslint/utils": "5.52.0", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", - "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", - "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", - "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.52.0", - "@typescript-eslint/utils": "5.52.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", - "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", - "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.52.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", - "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "source-map": "^0.6.1" - } - }, - "node_modules/@vue/compiler-core/node_modules/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, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", - "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/compiler-core": "3.2.47", - "@vue/shared": "3.2.47" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", - "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.47", - "@vue/compiler-dom": "3.2.47", - "@vue/compiler-ssr": "3.2.47", - "@vue/reactivity-transform": "3.2.47", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7", - "postcss": "^8.1.10", - "source-map": "^0.6.1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/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, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", - "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/compiler-dom": "3.2.47", - "@vue/shared": "3.2.47" - } - }, - "node_modules/@vue/reactivity-transform": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", - "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.47", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7" - } - }, - "node_modules/@vue/shared": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", - "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==", - "dev": true, - "peer": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "devOptional": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/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, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "devOptional": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", - "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", - "optional": true, - "dependencies": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/agentkeepalive/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "optional": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "optional": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-sequence-parser": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", - "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", - "dev": true - }, - "node_modules/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==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/app-root-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", - "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" - }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/are-we-there-yet/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "optional": true, - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cacache/node_modules/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==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001452", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz", - "integrity": "sha512-Lkp0vFjMkBB3GTpLR8zk4NwW5EdRdnitwYJHDOOKIU85x4ckYCPQ+9WlVvSVClHxVReefkUMtWZH2l9KGlD51w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/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, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/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==", - "dependencies": { - "chalk": "^4.0.0", - "highlight.js": "^10.7.1", - "mz": "^2.4.0", - "parse5": "^5.1.1", - "parse5-htmlparser2-tree-adapter": "^6.0.0", - "yargs": "^16.0.0" - }, - "bin": { - "highlight": "bin/highlight" - }, - "engines": { - "node": ">=8.0.0", - "npm": ">=5.0.0" - } - }, - "node_modules/cli-highlight/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cli-highlight/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cli-highlight/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cli-highlight/node_modules/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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/cli-highlight/node_modules/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==" - }, - "node_modules/cli-highlight/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-highlight/node_modules/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==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-highlight/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cli-highlight/node_modules/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==", - "engines": { - "node": ">=10" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/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==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "node_modules/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==", - "devOptional": true - }, - "node_modules/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, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/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, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.295", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz", - "integrity": "sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==", - "dev": true - }, - "node_modules/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==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/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==", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/env-cmd": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz", - "integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==", - "dev": true, - "dependencies": { - "commander": "^4.0.0", - "cross-spawn": "^7.0.0" - }, - "bin": { - "env-cmd": "bin/env-cmd.js" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/env-cmd/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "optional": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", - "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/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, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/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, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/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, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/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==", - "dev": true - }, - "node_modules/eslint/node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/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 - }, - "node_modules/eslint/node_modules/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/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, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "peer": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express-winston": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.2.0.tgz", - "integrity": "sha512-EMD74g63nVHi7pFleQw7KHCxiA1pjF5uCwbCfzGqmFxs9KvlDPIVS3cMGpULm6MshExMT9TjC3SqmRGB9kb7yw==", - "dependencies": { - "chalk": "^2.4.2", - "lodash": "^4.17.21" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "winston": ">=3.x <4" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/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==" - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/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, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/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==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/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, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/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, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/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==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "optional": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" - }, - "node_modules/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==", - "engines": { - "node": "*" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "optional": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "optional": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "optional": true, - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "node_modules/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, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "devOptional": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "optional": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "optional": true - }, - "node_modules/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==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/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, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "optional": true - }, - "node_modules/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, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "devOptional": true - }, - "node_modules/javascript-natural-sort": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", - "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", - "dev": true - }, - "node_modules/jose": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.4.tgz", - "integrity": "sha512-94FdcR8felat4vaTJyL/WVdtlWLlsnLMZP8v+A0Vru18K3bQ22vn7TtpVh3JlgBFNIlYOUlGqwp/MjRPOnIyCQ==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/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 - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/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==" - }, - "node_modules/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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/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, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/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 - }, - "node_modules/logform": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", - "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", - "dependencies": { - "@colors/colors": "1.5.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true - }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "peer": true, - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, - "node_modules/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==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true - }, - "node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "optional": true, - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/make-fetch-happen/node_modules/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==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/marked": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz", - "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==", - "dev": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "optional": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" - }, - "node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "optional": true, - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/node-gyp/node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "optional": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/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==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "optional": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "optional": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/nodemon": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", - "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", - "dev": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "optional": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/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, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" - }, - "node_modules/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==", - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/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, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "optional": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "optional": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/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==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/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 - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/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==" - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=4" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "optional": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", - "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/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, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/shiki": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.1.tgz", - "integrity": "sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw==", - "dev": true, - "dependencies": { - "ansi-sequence-parser": "^1.1.0", - "jsonc-parser": "^3.2.0", - "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", - "dev": true, - "dependencies": { - "semver": "~7.0.0" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "optional": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "optional": true, - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "optional": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true, - "peer": true - }, - "node_modules/sqlite3": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.4.tgz", - "integrity": "sha512-i0UlWAzPlzX3B5XP2cYuhWQJsTtlMD6obOa1PgeEQ4DHEXUuyJkgv50I3isqZAP5oFc2T8OFvakmDh2W6I+YpA==", - "hasInstallScript": true, - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.0", - "node-addon-api": "^4.2.0", - "tar": "^6.1.11" - }, - "optionalDependencies": { - "node-gyp": "8.x" - }, - "peerDependencies": { - "node-gyp": "8.x" - }, - "peerDependenciesMeta": { - "node-gyp": { - "optional": true - } - } - }, - "node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "optional": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tar": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", - "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", - "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/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, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/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, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/touch/node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/triple-beam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "devOptional": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/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, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typedoc": { - "version": "0.23.25", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.25.tgz", - "integrity": "sha512-O1he153qVyoCgJYSvIyY3bPP1wAJTegZfa6tL3APinSZhJOf8CSd8F/21M6ex8pUY/fuY6n0jAsT4fIuMGA6sA==", - "dev": true, - "dependencies": { - "lunr": "^2.3.9", - "marked": "^4.2.12", - "minimatch": "^6.1.6", - "shiki": "^0.14.1" - }, - "bin": { - "typedoc": "bin/typedoc" - }, - "engines": { - "node": ">= 14.14" - }, - "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x" - } - }, - "node_modules/typedoc/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", - "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typeorm": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", - "integrity": "sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==", - "dependencies": { - "@sqltools/formatter": "^1.2.5", - "app-root-path": "^3.1.0", - "buffer": "^6.0.3", - "chalk": "^4.1.2", - "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", - "debug": "^4.3.4", - "dotenv": "^16.0.3", - "glob": "^8.1.0", - "js-yaml": "^4.1.0", - "mkdirp": "^2.1.3", - "reflect-metadata": "^0.1.13", - "sha.js": "^2.4.11", - "tslib": "^2.5.0", - "uuid": "^9.0.0", - "xml2js": "^0.4.23", - "yargs": "^17.6.2" - }, - "bin": { - "typeorm": "cli.js", - "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", - "typeorm-ts-node-esm": "cli-ts-node-esm.js" - }, - "engines": { - "node": ">= 12.9.0" - }, - "funding": { - "url": "https://opencollective.com/typeorm" - }, - "peerDependencies": { - "@google-cloud/spanner": "^5.18.0", - "@sap/hana-client": "^2.12.25", - "better-sqlite3": "^7.1.2 || ^8.0.0", - "hdb-pool": "^0.1.6", - "ioredis": "^5.0.4", - "mongodb": "^3.6.0", - "mssql": "^7.3.0", - "mysql2": "^2.2.5 || ^3.0.1", - "oracledb": "^5.1.0", - "pg": "^8.5.1", - "pg-native": "^3.0.0", - "pg-query-stream": "^4.0.0", - "redis": "^3.1.1 || ^4.0.0", - "sql.js": "^1.4.0", - "sqlite3": "^5.0.3", - "ts-node": "^10.7.0", - "typeorm-aurora-data-api-driver": "^2.0.0" - }, - "peerDependenciesMeta": { - "@google-cloud/spanner": { - "optional": true - }, - "@sap/hana-client": { - "optional": true - }, - "better-sqlite3": { - "optional": true - }, - "hdb-pool": { - "optional": true - }, - "ioredis": { - "optional": true - }, - "mongodb": { - "optional": true - }, - "mssql": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "oracledb": { - "optional": true - }, - "pg": { - "optional": true - }, - "pg-native": { - "optional": true - }, - "pg-query-stream": { - "optional": true - }, - "redis": { - "optional": true - }, - "sql.js": { - "optional": true - }, - "sqlite3": { - "optional": true - }, - "ts-node": { - "optional": true - }, - "typeorm-aurora-data-api-driver": { - "optional": true - } - } - }, - "node_modules/typeorm/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/typeorm/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/typeorm/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typeorm/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/typeorm/node_modules/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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/typeorm/node_modules/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==" - }, - "node_modules/typeorm/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typeorm/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/typeorm/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/typeorm/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typeorm/node_modules/mkdirp": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.3.tgz", - "integrity": "sha512-sjAkg21peAG9HS+Dkx7hlG9Ztx7HLeKnvB3NQRcu/mltCVmvkF0pisbiTSfDVYTT86XEfZrTUosLdZLStquZUw==", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typeorm/node_modules/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==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/typeorm/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "devOptional": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "optional": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "optional": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" + "name": "@crosslab/service-experiment", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@crosslab/service-experiment", + "license": "UNLICENSED", + "dependencies": { + "@cross-lab-project/api-client": "file:../../clients/api/js", + "@crosslab/service-common": "file:../common", + "ajv-formats": "^2.1.1", + "body-parser": "^1.20.0", + "express": "^4.18.1", + "express-winston": "^4.2.0", + "jose": "^4.10.0", + "node-fetch": "^2.6.7", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", + "winston": "^3.8.2" + }, + "bin": { + "crosslab-experiment-service": "app/index.js" + }, + "devDependencies": { + "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", + "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/body-parser": "^1.19.2", + "@types/express": "^4.17.13", + "@types/node": "^18.0.3", + "@types/node-fetch": "^2.6.1", + "@types/ws": "^8.5.3", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "env-cmd": "^10.1.0", + "eslint": "^8.34.0", + "nodemon": "^2.0.19", + "prettier": "^2.7.1", + "ts-node": "^10.9.1", + "typedoc": "^0.23.20", + "typescript": "^4.7.4" + } + }, + "../../clients/api/js": { + "name": "@cross-lab-project/api-client", + "license": "ISC", + "dependencies": { + "ajv-formats": "^2.1.1", + "cross-fetch": "^3.1.5" + }, + "devDependencies": { + "@cross-lab-project/codegen-typescript-addon": "file:../../../helper/crosslab-typescript-addon", + "@cross-lab-project/openapi-codegen": "file:../../../helper/openapi-codegeneration", + "@cross-lab-project/tsdoc-theme": "file:../../../helper/tsdoc-theme", + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/node": "^18.0.3", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "eslint": "^8.34.0", + "typedoc": "^0.23.20", + "typescript": "^4.7.4" + } + }, + "../../helper/crosslab-typescript-addon": { + "name": "@cross-lab-project/codegen-typescript-addon", + "dev": true, + "license": "UNLICENSED", + "devDependencies": { + "@cross-lab-project/openapi-codegen": "file:../openapi-codegeneration", + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/node": "^17.0.35", + "@types/nunjucks": "^3.2.1", + "@types/prettier": "^2.6.3", + "@types/seedrandom": "^3.0.2", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "copyfiles": "^2.4.1", + "eslint": "^8.34.0", + "openapi-types": "^12.0.0", + "tsc-watch": "^5.0.3", + "typescript": "^4.6.4" + }, + "peerDependencies": { + "@apidevtools/swagger-parser": "^10.1.0", + "@cross-lab-project/openapi-codegen": "file:../openapi-codegeneration", + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "nunjucks": "^3.2.3", + "prettier": "^2.6.2" + } + }, + "../../helper/openapi-codegeneration": { + "name": "@cross-lab-project/openapi-codegen", + "dev": true, + "license": "UNLICENSED", + "dependencies": { + "@apidevtools/swagger-parser": "^10.1.0", + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "commander": "^9.4.1", + "deterministic-json-schema-faker": "^0.5.0-rcv.46", + "json-schema-merge-allof": "^0.8.1", + "json-schema-to-typescript": "^10.1.5", + "nunjucks": "^3.2.3", + "prettier": "^2.6.2", + "quicktype-core": "^6.1.0", + "seedrandom": "^3.0.5", + "tiny-typed-emitter": "^2.1.0" + }, + "bin": { + "openapi-codegen": "lib/cjs/index.js" + }, + "devDependencies": { + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/node": "^17.0.45", + "@types/nunjucks": "^3.2.1", + "@types/prettier": "^2.6.3", + "@types/seedrandom": "^3.0.2", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "eslint": "^8.34.0", + "openapi-types": "^12.0.0", + "tsc-watch": "^5.0.3", + "typescript": "^4.6.4" + } + }, + "../common": { + "name": "@crosslab/service-common", + "license": "UNLICENSED", + "dependencies": { + "jose": "^4.11.1" + }, + "devDependencies": { + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/mocha": "^10.0.1", + "@types/node": "^18.11.18", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "eslint": "^8.34.0", + "mocha": "^10.2.0", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", + "typescript": "^4.9.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", + "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", + "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.7", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.8", + "@babel/parser": "^7.17.8", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", + "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cross-lab-project/api-client": { + "resolved": "../../clients/api/js", + "link": true + }, + "node_modules/@cross-lab-project/codegen-typescript-addon": { + "resolved": "../../helper/crosslab-typescript-addon", + "link": true + }, + "node_modules/@cross-lab-project/openapi-codegen": { + "resolved": "../../helper/openapi-codegeneration", + "link": true + }, + "node_modules/@crosslab/service-common": { + "resolved": "../common", + "link": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "devOptional": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "devOptional": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/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 + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "optional": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "devOptional": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "devOptional": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/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==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/@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, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@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, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@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, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/fs/node_modules/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==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/fs/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "optional": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@sqltools/formatter": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", + "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.0.0.tgz", + "integrity": "sha512-Tyuk5ZY4a0e2MNFLdluQO9F6d1awFQYXVVujEPFfvKPPXz8DADNHzz73NMhwCSXGSuGGZcA/rKOyZBrxVNMxaA==", + "dev": true, + "dependencies": { + "@babel/core": "7.17.8", + "@babel/generator": "7.17.7", + "@babel/parser": "7.18.9", + "@babel/traverse": "7.17.3", + "@babel/types": "7.17.0", + "javascript-natural-sort": "0.7.1", + "lodash": "4.17.21" + }, + "peerDependencies": { + "@vue/compiler-sfc": "3.x", + "prettier": "2.x" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "devOptional": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "devOptional": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "devOptional": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "devOptional": true + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", + "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==", + "devOptional": true + }, + "node_modules/@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@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==", + "dev": true + }, + "node_modules/@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==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/triple-beam": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz", + "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" + }, + "node_modules/@types/ws": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", + "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/type-utils": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", + "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", + "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", + "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", + "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", + "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", + "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/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, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", + "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", + "dev": true, + "peer": true, + "dependencies": { + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", + "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/compiler-dom": "3.2.47", + "@vue/compiler-ssr": "3.2.47", + "@vue/reactivity-transform": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-sfc/node_modules/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, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", + "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", + "dev": true, + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/@vue/reactivity-transform": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", + "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "node_modules/@vue/shared": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", + "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==", + "dev": true, + "peer": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "devOptional": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/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, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "devOptional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "optional": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/agentkeepalive/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "optional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", + "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", + "dev": true + }, + "node_modules/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==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/are-we-there-yet/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "devOptional": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacache/node_modules/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==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001452", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz", + "integrity": "sha512-Lkp0vFjMkBB3GTpLR8zk4NwW5EdRdnitwYJHDOOKIU85x4ckYCPQ+9WlVvSVClHxVReefkUMtWZH2l9KGlD51w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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==", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/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==" + }, + "node_modules/cli-highlight/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/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==", + "engines": { + "node": ">=10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/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==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/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==", + "devOptional": true + }, + "node_modules/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, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "devOptional": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/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, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.295", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz", + "integrity": "sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==", + "dev": true + }, + "node_modules/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==" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/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==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/env-cmd": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz", + "integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==", + "dev": true, + "dependencies": { + "commander": "^4.0.0", + "cross-spawn": "^7.0.0" + }, + "bin": { + "env-cmd": "bin/env-cmd.js" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/env-cmd/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "optional": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/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, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/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, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/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, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/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==", + "dev": true + }, + "node_modules/eslint/node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/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 + }, + "node_modules/eslint/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/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, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "peer": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-winston": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.2.0.tgz", + "integrity": "sha512-EMD74g63nVHi7pFleQw7KHCxiA1pjF5uCwbCfzGqmFxs9KvlDPIVS3cMGpULm6MshExMT9TjC3SqmRGB9kb7yw==", + "dependencies": { + "chalk": "^2.4.2", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "winston": ">=3.x <4" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/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==" + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "node_modules/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, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/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, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "optional": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/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==", + "engines": { + "node": "*" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "optional": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/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, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "devOptional": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "optional": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "optional": true + }, + "node_modules/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==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/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, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "optional": true + }, + "node_modules/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, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "devOptional": true + }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "dev": true + }, + "node_modules/jose": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.4.tgz", + "integrity": "sha512-94FdcR8felat4vaTJyL/WVdtlWLlsnLMZP8v+A0Vru18K3bQ22vn7TtpVh3JlgBFNIlYOUlGqwp/MjRPOnIyCQ==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/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 + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/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==" + }, + "node_modules/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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/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, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/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 + }, + "node_modules/logform": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", + "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "dependencies": { + "@colors/colors": "1.5.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "peer": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/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==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "devOptional": true + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/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==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/marked": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz", + "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/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==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "node_modules/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==", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "peer": true, + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/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, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/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==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/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 + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/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==" + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/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, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/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, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.1.tgz", + "integrity": "sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw==", + "dev": true, + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "optional": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true, + "peer": true + }, + "node_modules/sqlite3": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz", + "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", + "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/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, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/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, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "devOptional": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/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, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedoc": { + "version": "0.23.25", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.25.tgz", + "integrity": "sha512-O1he153qVyoCgJYSvIyY3bPP1wAJTegZfa6tL3APinSZhJOf8CSd8F/21M6ex8pUY/fuY6n0jAsT4fIuMGA6sA==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.2.12", + "minimatch": "^6.1.6", + "shiki": "^0.14.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x" + } + }, + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", + "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.15.tgz", + "integrity": "sha512-R4JSw8QjDP1W+ypeRz/XrCXIqubrLSnNAzJAp9EQSQIPHTv+YmUHZis8g08lOwFpuhqL9m8jkPSz8GWEKlU/ow==", + "dependencies": { + "@sqltools/formatter": "^1.2.5", + "app-root-path": "^3.1.0", + "buffer": "^6.0.3", + "chalk": "^4.1.2", + "cli-highlight": "^2.1.11", + "debug": "^4.3.4", + "dotenv": "^16.0.3", + "glob": "^8.1.0", + "mkdirp": "^2.1.3", + "reflect-metadata": "^0.1.13", + "sha.js": "^2.4.11", + "tslib": "^2.5.0", + "uuid": "^9.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "typeorm": "cli.js", + "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", + "typeorm-ts-node-esm": "cli-ts-node-esm.js" + }, + "engines": { + "node": ">= 12.9.0" + }, + "funding": { + "url": "https://opencollective.com/typeorm" + }, + "peerDependencies": { + "@google-cloud/spanner": "^5.18.0", + "@sap/hana-client": "^2.12.25", + "better-sqlite3": "^7.1.2 || ^8.0.0", + "hdb-pool": "^0.1.6", + "ioredis": "^5.0.4", + "mongodb": "^5.2.0", + "mssql": "^9.1.1", + "mysql2": "^2.2.5 || ^3.0.1", + "oracledb": "^5.1.0", + "pg": "^8.5.1", + "pg-native": "^3.0.0", + "pg-query-stream": "^4.0.0", + "redis": "^3.1.1 || ^4.0.0", + "sql.js": "^1.4.0", + "sqlite3": "^5.0.3", + "ts-node": "^10.7.0", + "typeorm-aurora-data-api-driver": "^2.0.0" + }, + "peerDependenciesMeta": { + "@google-cloud/spanner": { + "optional": true + }, + "@sap/hana-client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "hdb-pool": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mssql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "redis": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "ts-node": { + "optional": true + }, + "typeorm-aurora-data-api-driver": { + "optional": true + } + } + }, + "node_modules/typeorm/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/typeorm/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typeorm/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/typeorm/node_modules/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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/typeorm/node_modules/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==" + }, + "node_modules/typeorm/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/typeorm/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typeorm/node_modules/mkdirp": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.3.tgz", + "integrity": "sha512-sjAkg21peAG9HS+Dkx7hlG9Ztx7HLeKnvB3NQRcu/mltCVmvkF0pisbiTSfDVYTT86XEfZrTUosLdZLStquZUw==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typeorm/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "devOptional": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "devOptional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/winston": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "dependencies": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston-transport/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/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==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "dev": true - }, - "node_modules/vscode-textmate": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", - "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", - "dev": true - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/winston": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", - "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", - "dependencies": { - "@colors/colors": "1.5.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.5.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", - "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 6.4.0" - } - }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/winston-transport/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/winston/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/winston/node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/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==" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } - } } diff --git a/services/experiment/package.json b/services/experiment/package.json index 4322894f..636f00b0 100644 --- a/services/experiment/package.json +++ b/services/experiment/package.json @@ -1,59 +1,59 @@ { - "name": "@crosslab/service-experiment", - "dockerName": "experiment-service", - "description": "", - "bin": { - "crosslab-experiment-service": "./app/index.js" - }, - "files": [ - "app" - ], - "scripts": { - "openapi-lint": "npx --yes @redocly/cli lint ./api/openapi.yml", - "openapi-bundle": "npx --yes @redocly/cli bundle ./api/openapi.yml --output dist/openapi.json", - "watch-openapi": "npx --yes chokidar-cli 'api/**/*.yml' -c 'npm run openapi-bundle'", - "watch-rapidoc": "npx --yes browser-sync start --server --startPath 'api/rapidoc.html' --files 'dist/openapi.json'", - "build-generate-code": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service -o src/generated", - "build-compile": "tsc", - "build": "npm run build-generate-code && npm run build-compile", - "start": "node app/index.js", - "dev": "env-cmd -e development npx nodemon src/index.ts", - "format": "npx prettier src --write", - "doc": "typedoc --options ./typedoc.json", - "lint": "eslint ." - }, - "author": "Johannes Nau", - "license": "UNLICENSED", - "devDependencies": { - "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", - "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/body-parser": "^1.19.2", - "@types/express": "^4.17.13", - "@types/node": "^18.0.3", - "@types/node-fetch": "^2.6.1", - "@types/ws": "^8.5.3", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "env-cmd": "^10.1.0", - "eslint": "^8.34.0", - "nodemon": "^2.0.19", - "prettier": "^2.7.1", - "ts-node": "^10.9.1", - "typedoc": "^0.23.20", - "typescript": "^4.7.4" - }, - "dependencies": { - "@cross-lab-project/api-client": "file:../../clients/api/js", - "@crosslab/service-common": "file:../common", - "ajv-formats": "^2.1.1", - "body-parser": "^1.20.0", - "express": "^4.18.1", - "express-winston": "^4.2.0", - "jose": "^4.10.0", - "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", - "winston": "^3.8.2" - } -} + "name": "@crosslab/service-experiment", + "dockerName": "experiment-service", + "description": "", + "bin": { + "crosslab-experiment-service": "./app/index.js" + }, + "files": [ + "app" + ], + "scripts": { + "openapi-lint": "npx --yes @redocly/cli lint ./api/openapi.yml", + "openapi-bundle": "npx --yes @redocly/cli bundle ./api/openapi.yml --output dist/openapi.json", + "watch-openapi": "npx --yes chokidar-cli 'api/**/*.yml' -c 'npm run openapi-bundle'", + "watch-rapidoc": "npx --yes browser-sync start --server --startPath 'api/rapidoc.html' --files 'dist/openapi.json'", + "build-generate-code": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service -o src/generated", + "build-compile": "tsc", + "build": "npm run build-generate-code && npm run build-compile", + "start": "node app/index.js", + "dev": "env-cmd -e development npx nodemon src/index.ts", + "format": "npx prettier src --write", + "doc": "typedoc --options ./typedoc.json", + "lint": "eslint ." + }, + "author": "Johannes Nau", + "license": "UNLICENSED", + "devDependencies": { + "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", + "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/body-parser": "^1.19.2", + "@types/express": "^4.17.13", + "@types/node": "^18.0.3", + "@types/node-fetch": "^2.6.1", + "@types/ws": "^8.5.3", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "env-cmd": "^10.1.0", + "eslint": "^8.34.0", + "nodemon": "^2.0.19", + "prettier": "^2.7.1", + "ts-node": "^10.9.1", + "typedoc": "^0.23.20", + "typescript": "^4.7.4" + }, + "dependencies": { + "@cross-lab-project/api-client": "file:../../clients/api/js", + "@crosslab/service-common": "file:../common", + "ajv-formats": "^2.1.1", + "body-parser": "^1.20.0", + "express": "^4.18.1", + "express-winston": "^4.2.0", + "jose": "^4.10.0", + "node-fetch": "^2.6.7", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", + "winston": "^3.8.2" + } +} \ No newline at end of file diff --git a/services/federation/package-lock.json b/services/federation/package-lock.json index 77df3eee..6b2aa564 100644 --- a/services/federation/package-lock.json +++ b/services/federation/package-lock.json @@ -1,5828 +1,5780 @@ { - "name": "@crosslab/service-federation", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@crosslab/service-federation", - "license": "UNLICENSED", - "dependencies": { - "@crosslab/service-common": "file:../common", - "ajv-formats": "^2.1.1", - "body-parser": "^1.20.0", - "express": "^4.18.1", - "jose": "^4.10.0", - "mysql": "^2.18.1", - "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6" - }, - "bin": { - "crosslab-federation-service": "app/index.js" - }, - "devDependencies": { - "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", - "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/body-parser": "^1.19.2", - "@types/express": "^4.17.13", - "@types/node": "^17.0.41", - "@types/node-fetch": "^2.6.1", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "env-cmd": "^10.1.0", - "eslint": "^8.34.0", - "nodemon": "^2.0.19", - "prettier": "^2.7.1", - "ts-node": "^10.9.1", - "typescript": "^4.7.3" - } - }, - "../../helper/crosslab-typescript-addon": { - "dev": true, - "license": "UNLICENSED", - "devDependencies": { - "@cross-lab-project/openapi-codegen": "file:../openapi-codegeneration", - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/node": "^17.0.35", - "@types/nunjucks": "^3.2.1", - "@types/prettier": "^2.6.3", - "@types/seedrandom": "^3.0.2", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "copyfiles": "^2.4.1", - "eslint": "^8.34.0", - "openapi-types": "^12.0.0", - "tsc-watch": "^5.0.3", - "typescript": "^4.6.4" - }, - "peerDependencies": { - "@apidevtools/swagger-parser": "^10.1.0", - "@cross-lab-project/openapi-codegen": "file:../openapi-codegeneration", - "ajv": "^8.11.0", - "ajv-formats": "^2.1.1", - "nunjucks": "^3.2.3", - "prettier": "^2.6.2" - } - }, - "../../helper/openapi-codegeneration": { - "dev": true, - "license": "UNLICENSED", - "dependencies": { - "@apidevtools/swagger-parser": "^10.1.0", - "ajv": "^8.11.0", - "ajv-formats": "^2.1.1", - "commander": "^9.4.1", - "deterministic-json-schema-faker": "^0.5.0-rcv.46", - "json-schema-to-typescript": "^10.1.5", - "nunjucks": "^3.2.3", - "prettier": "^2.6.2", - "quicktype-core": "^6.1.0", - "seedrandom": "^3.0.5", - "tiny-typed-emitter": "^2.1.0" - }, - "bin": { - "openapi-codegen": "lib/cjs/index.js" - }, - "devDependencies": { - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/node": "^17.0.45", - "@types/nunjucks": "^3.2.1", - "@types/prettier": "^2.6.3", - "@types/seedrandom": "^3.0.2", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "eslint": "^8.34.0", - "openapi-types": "^12.0.0", - "tsc-watch": "^5.0.3", - "typescript": "^4.6.4" - } - }, - "../common": { - "license": "UNLICENSED", - "dependencies": { - "jose": "^4.11.1" - }, - "devDependencies": { - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/node": "^18.11.18", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "eslint": "^8.34.0", - "typescript": "^4.9.4" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", - "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", - "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.7", - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helpers": "^7.17.8", - "@babel/parser": "^7.17.8", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", - "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.20.11", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", - "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.10", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", - "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.20.13", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/generator": { - "version": "7.20.14", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", - "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/traverse": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", - "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.7", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.13", - "@babel/types": "^7.20.7", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", - "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/parser": { - "version": "7.20.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", - "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", - "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@cross-lab-project/codegen-typescript-addon": { - "resolved": "../../helper/crosslab-typescript-addon", - "link": true - }, - "node_modules/@cross-lab-project/openapi-codegen": { - "resolved": "../../helper/openapi-codegeneration", - "link": true - }, - "node_modules/@crosslab/service-common": { - "resolved": "../common", - "link": true - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/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 - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "optional": true - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "devOptional": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "devOptional": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", - "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", - "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/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==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/@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, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@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, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@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, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "optional": true, - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/@npmcli/fs/node_modules/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==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/fs/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "optional": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@sqltools/formatter": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", - "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "optional": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.0.0.tgz", - "integrity": "sha512-Tyuk5ZY4a0e2MNFLdluQO9F6d1awFQYXVVujEPFfvKPPXz8DADNHzz73NMhwCSXGSuGGZcA/rKOyZBrxVNMxaA==", - "dev": true, - "dependencies": { - "@babel/core": "7.17.8", - "@babel/generator": "7.17.7", - "@babel/parser": "7.18.9", - "@babel/traverse": "7.17.3", - "@babel/types": "7.17.0", - "javascript-natural-sort": "0.7.1", - "lodash": "4.17.21" - }, - "peerDependencies": { - "@vue/compiler-sfc": "3.x", - "prettier": "2.x" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "devOptional": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "devOptional": true - }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.33", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", - "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", - "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", - "devOptional": true - }, - "node_modules/@types/node-fetch": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", - "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, - "node_modules/@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==", - "dev": true - }, - "node_modules/@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==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "node_modules/@types/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", - "dev": true, - "dependencies": { - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", - "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/type-utils": "5.52.0", - "@typescript-eslint/utils": "5.52.0", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", - "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", - "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", - "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.52.0", - "@typescript-eslint/utils": "5.52.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", - "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", - "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/visitor-keys": "5.52.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", - "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.52.0", - "@typescript-eslint/types": "5.52.0", - "@typescript-eslint/typescript-estree": "5.52.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/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==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.52.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", - "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.52.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", - "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "source-map": "^0.6.1" - } - }, - "node_modules/@vue/compiler-core/node_modules/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, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", - "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/compiler-core": "3.2.47", - "@vue/shared": "3.2.47" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", - "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.47", - "@vue/compiler-dom": "3.2.47", - "@vue/compiler-ssr": "3.2.47", - "@vue/reactivity-transform": "3.2.47", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7", - "postcss": "^8.1.10", - "source-map": "^0.6.1" - } - }, - "node_modules/@vue/compiler-sfc/node_modules/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, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", - "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", - "dev": true, - "peer": true, - "dependencies": { - "@vue/compiler-dom": "3.2.47", - "@vue/shared": "3.2.47" - } - }, - "node_modules/@vue/reactivity-transform": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", - "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.47", - "@vue/shared": "3.2.47", - "estree-walker": "^2.0.2", - "magic-string": "^0.25.7" - } - }, - "node_modules/@vue/shared": { - "version": "3.2.47", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", - "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==", - "dev": true, - "peer": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "devOptional": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/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, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "devOptional": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", - "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", - "optional": true, - "dependencies": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/agentkeepalive/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "optional": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "optional": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/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, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/app-root-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", - "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" - }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", - "engines": { - "node": "*" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "optional": true, - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cacache/node_modules/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==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001452", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz", - "integrity": "sha512-Lkp0vFjMkBB3GTpLR8zk4NwW5EdRdnitwYJHDOOKIU85x4ckYCPQ+9WlVvSVClHxVReefkUMtWZH2l9KGlD51w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/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, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/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, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/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==", - "dependencies": { - "chalk": "^4.0.0", - "highlight.js": "^10.7.1", - "mz": "^2.4.0", - "parse5": "^5.1.1", - "parse5-htmlparser2-tree-adapter": "^6.0.0", - "yargs": "^16.0.0" - }, - "bin": { - "highlight": "bin/highlight" - }, - "engines": { - "node": ">=8.0.0", - "npm": ">=5.0.0" - } - }, - "node_modules/cli-highlight/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cli-highlight/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cli-highlight/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cli-highlight/node_modules/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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/cli-highlight/node_modules/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==" - }, - "node_modules/cli-highlight/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-highlight/node_modules/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==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-highlight/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cli-highlight/node_modules/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==", - "engines": { - "node": ">=10" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/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, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/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==", - "devOptional": true - }, - "node_modules/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, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/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, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.295", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz", - "integrity": "sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==", - "dev": true - }, - "node_modules/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==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/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==", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/env-cmd": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz", - "integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==", - "dev": true, - "dependencies": { - "commander": "^4.0.0", - "cross-spawn": "^7.0.0" - }, - "bin": { - "env-cmd": "bin/env-cmd.js" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/env-cmd/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "optional": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.34.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", - "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/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, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/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, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/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, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/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==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/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==", - "dev": true - }, - "node_modules/eslint/node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/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 - }, - "node_modules/eslint/node_modules/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, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/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, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "peer": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/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==" - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/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, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/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==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/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, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/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, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/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==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "optional": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" - }, - "node_modules/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==", - "engines": { - "node": "*" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "optional": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "optional": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "optional": true, - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "node_modules/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, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "devOptional": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "optional": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "optional": true - }, - "node_modules/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==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/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, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "optional": true - }, - "node_modules/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, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "devOptional": true - }, - "node_modules/javascript-natural-sort": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", - "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", - "dev": true - }, - "node_modules/jose": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.4.tgz", - "integrity": "sha512-94FdcR8felat4vaTJyL/WVdtlWLlsnLMZP8v+A0Vru18K3bQ22vn7TtpVh3JlgBFNIlYOUlGqwp/MjRPOnIyCQ==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/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 - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/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==" - }, - "node_modules/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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/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, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/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 - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", - "dev": true, - "peer": true, - "dependencies": { - "sourcemap-codec": "^1.4.8" - } - }, - "node_modules/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==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true - }, - "node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "optional": true, - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/make-fetch-happen/node_modules/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==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "optional": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mysql": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", - "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", - "dependencies": { - "bignumber.js": "9.0.0", - "readable-stream": "2.3.7", - "safe-buffer": "5.1.2", - "sqlstring": "2.3.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mysql/node_modules/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==" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" - }, - "node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "optional": true, - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/node-gyp/node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "optional": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/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==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "optional": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/nodemon": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", - "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", - "dev": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "optional": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/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, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" - }, - "node_modules/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==", - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "peer": true, - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/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, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "optional": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "optional": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/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==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/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 - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/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==" - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/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==" - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=4" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "optional": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/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, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", - "dev": true, - "dependencies": { - "semver": "~7.0.0" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "optional": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "optional": true, - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "optional": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true, - "peer": true - }, - "node_modules/sqlite3": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.4.tgz", - "integrity": "sha512-i0UlWAzPlzX3B5XP2cYuhWQJsTtlMD6obOa1PgeEQ4DHEXUuyJkgv50I3isqZAP5oFc2T8OFvakmDh2W6I+YpA==", - "hasInstallScript": true, - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.0", - "node-addon-api": "^4.2.0", - "tar": "^6.1.11" - }, - "optionalDependencies": { - "node-gyp": "8.x" - }, - "peerDependencies": { - "node-gyp": "8.x" - }, - "peerDependenciesMeta": { - "node-gyp": { - "optional": true - } - } - }, - "node_modules/sqlstring": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", - "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "optional": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/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==" - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/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, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/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, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tar": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", - "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", - "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/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, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/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, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/touch/node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "devOptional": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/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, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typeorm": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", - "integrity": "sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==", - "dependencies": { - "@sqltools/formatter": "^1.2.5", - "app-root-path": "^3.1.0", - "buffer": "^6.0.3", - "chalk": "^4.1.2", - "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", - "debug": "^4.3.4", - "dotenv": "^16.0.3", - "glob": "^8.1.0", - "js-yaml": "^4.1.0", - "mkdirp": "^2.1.3", - "reflect-metadata": "^0.1.13", - "sha.js": "^2.4.11", - "tslib": "^2.5.0", - "uuid": "^9.0.0", - "xml2js": "^0.4.23", - "yargs": "^17.6.2" - }, - "bin": { - "typeorm": "cli.js", - "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", - "typeorm-ts-node-esm": "cli-ts-node-esm.js" - }, - "engines": { - "node": ">= 12.9.0" - }, - "funding": { - "url": "https://opencollective.com/typeorm" - }, - "peerDependencies": { - "@google-cloud/spanner": "^5.18.0", - "@sap/hana-client": "^2.12.25", - "better-sqlite3": "^7.1.2 || ^8.0.0", - "hdb-pool": "^0.1.6", - "ioredis": "^5.0.4", - "mongodb": "^3.6.0", - "mssql": "^7.3.0", - "mysql2": "^2.2.5 || ^3.0.1", - "oracledb": "^5.1.0", - "pg": "^8.5.1", - "pg-native": "^3.0.0", - "pg-query-stream": "^4.0.0", - "redis": "^3.1.1 || ^4.0.0", - "sql.js": "^1.4.0", - "sqlite3": "^5.0.3", - "ts-node": "^10.7.0", - "typeorm-aurora-data-api-driver": "^2.0.0" - }, - "peerDependenciesMeta": { - "@google-cloud/spanner": { - "optional": true - }, - "@sap/hana-client": { - "optional": true - }, - "better-sqlite3": { - "optional": true - }, - "hdb-pool": { - "optional": true - }, - "ioredis": { - "optional": true - }, - "mongodb": { - "optional": true - }, - "mssql": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "oracledb": { - "optional": true - }, - "pg": { - "optional": true - }, - "pg-native": { - "optional": true - }, - "pg-query-stream": { - "optional": true - }, - "redis": { - "optional": true - }, - "sql.js": { - "optional": true - }, - "sqlite3": { - "optional": true - }, - "ts-node": { - "optional": true - }, - "typeorm-aurora-data-api-driver": { - "optional": true - } - } - }, - "node_modules/typeorm/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/typeorm/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/typeorm/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typeorm/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/typeorm/node_modules/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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/typeorm/node_modules/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==" - }, - "node_modules/typeorm/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typeorm/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/typeorm/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/typeorm/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typeorm/node_modules/mkdirp": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.3.tgz", - "integrity": "sha512-sjAkg21peAG9HS+Dkx7hlG9Ztx7HLeKnvB3NQRcu/mltCVmvkF0pisbiTSfDVYTT86XEfZrTUosLdZLStquZUw==", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typeorm/node_modules/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==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/typeorm/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "devOptional": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "optional": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "optional": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" + "name": "@crosslab/service-federation", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@crosslab/service-federation", + "license": "UNLICENSED", + "dependencies": { + "@crosslab/service-common": "file:../common", + "ajv-formats": "^2.1.1", + "body-parser": "^1.20.0", + "express": "^4.18.1", + "jose": "^4.10.0", + "mysql": "^2.18.1", + "node-fetch": "^2.6.7", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15" + }, + "bin": { + "crosslab-federation-service": "app/index.js" + }, + "devDependencies": { + "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", + "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/body-parser": "^1.19.2", + "@types/express": "^4.17.13", + "@types/node": "^17.0.41", + "@types/node-fetch": "^2.6.1", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "env-cmd": "^10.1.0", + "eslint": "^8.34.0", + "nodemon": "^2.0.19", + "prettier": "^2.7.1", + "ts-node": "^10.9.1", + "typescript": "^4.7.3" + } + }, + "../../helper/crosslab-typescript-addon": { + "name": "@cross-lab-project/codegen-typescript-addon", + "dev": true, + "license": "UNLICENSED", + "devDependencies": { + "@cross-lab-project/openapi-codegen": "file:../openapi-codegeneration", + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/node": "^17.0.35", + "@types/nunjucks": "^3.2.1", + "@types/prettier": "^2.6.3", + "@types/seedrandom": "^3.0.2", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "copyfiles": "^2.4.1", + "eslint": "^8.34.0", + "openapi-types": "^12.0.0", + "tsc-watch": "^5.0.3", + "typescript": "^4.6.4" + }, + "peerDependencies": { + "@apidevtools/swagger-parser": "^10.1.0", + "@cross-lab-project/openapi-codegen": "file:../openapi-codegeneration", + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "nunjucks": "^3.2.3", + "prettier": "^2.6.2" + } + }, + "../../helper/openapi-codegeneration": { + "name": "@cross-lab-project/openapi-codegen", + "dev": true, + "license": "UNLICENSED", + "dependencies": { + "@apidevtools/swagger-parser": "^10.1.0", + "ajv": "^8.11.0", + "ajv-formats": "^2.1.1", + "commander": "^9.4.1", + "deterministic-json-schema-faker": "^0.5.0-rcv.46", + "json-schema-merge-allof": "^0.8.1", + "json-schema-to-typescript": "^10.1.5", + "nunjucks": "^3.2.3", + "prettier": "^2.6.2", + "quicktype-core": "^6.1.0", + "seedrandom": "^3.0.5", + "tiny-typed-emitter": "^2.1.0" + }, + "bin": { + "openapi-codegen": "lib/cjs/index.js" + }, + "devDependencies": { + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/node": "^17.0.45", + "@types/nunjucks": "^3.2.1", + "@types/prettier": "^2.6.3", + "@types/seedrandom": "^3.0.2", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "eslint": "^8.34.0", + "openapi-types": "^12.0.0", + "tsc-watch": "^5.0.3", + "typescript": "^4.6.4" + } + }, + "../common": { + "name": "@crosslab/service-common", + "license": "UNLICENSED", + "dependencies": { + "jose": "^4.11.1" + }, + "devDependencies": { + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/mocha": "^10.0.1", + "@types/node": "^18.11.18", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "eslint": "^8.34.0", + "mocha": "^10.2.0", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", + "typescript": "^4.9.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz", + "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", + "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.7", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.8", + "@babel/parser": "^7.17.8", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", + "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.17.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz", + "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.13", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/generator": { + "version": "7.20.14", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz", + "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/traverse": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz", + "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.20.13", + "@babel/types": "^7.20.7", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", + "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/parser": { + "version": "7.20.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", + "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/types": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.17.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", + "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.3", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.3", + "@babel/types": "^7.17.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cross-lab-project/codegen-typescript-addon": { + "resolved": "../../helper/crosslab-typescript-addon", + "link": true + }, + "node_modules/@cross-lab-project/openapi-codegen": { + "resolved": "../../helper/openapi-codegeneration", + "link": true + }, + "node_modules/@crosslab/service-common": { + "resolved": "../common", + "link": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "devOptional": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "devOptional": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/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 + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "optional": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "devOptional": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "devOptional": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", + "integrity": "sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/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==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/@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, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@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, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@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, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/fs/node_modules/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==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/fs/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "optional": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@sqltools/formatter": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", + "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.0.0.tgz", + "integrity": "sha512-Tyuk5ZY4a0e2MNFLdluQO9F6d1awFQYXVVujEPFfvKPPXz8DADNHzz73NMhwCSXGSuGGZcA/rKOyZBrxVNMxaA==", + "dev": true, + "dependencies": { + "@babel/core": "7.17.8", + "@babel/generator": "7.17.7", + "@babel/parser": "7.18.9", + "@babel/traverse": "7.17.3", + "@babel/types": "7.17.0", + "javascript-natural-sort": "0.7.1", + "lodash": "4.17.21" + }, + "peerDependencies": { + "@vue/compiler-sfc": "3.x", + "prettier": "2.x" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "devOptional": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "devOptional": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "devOptional": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "devOptional": true + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "devOptional": true + }, + "node_modules/@types/node-fetch": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.2.tgz", + "integrity": "sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@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==", + "dev": true + }, + "node_modules/@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==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.52.0.tgz", + "integrity": "sha512-lHazYdvYVsBokwCdKOppvYJKaJ4S41CgKBcPvyd0xjZNbvQdhn/pnJlGtQksQ/NhInzdaeaSarlBjDXHuclEbg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/type-utils": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.52.0.tgz", + "integrity": "sha512-e2KiLQOZRo4Y0D/b+3y08i3jsekoSkOYStROYmPUnGMEoA0h+k2qOH5H6tcjIc68WDvGwH+PaOrP1XRzLJ6QlA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.52.0.tgz", + "integrity": "sha512-AR7sxxfBKiNV0FWBSARxM8DmNxrwgnYMPwmpkC1Pl1n+eT8/I2NAUPuwDy/FmDcC6F8pBfmOcaxcxRHspgOBMw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.52.0.tgz", + "integrity": "sha512-tEKuUHfDOv852QGlpPtB3lHOoig5pyFQN/cUiZtpw99D93nEBjexRLre5sQZlkMoHry/lZr8qDAt2oAHLKA6Jw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.52.0", + "@typescript-eslint/utils": "5.52.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.52.0.tgz", + "integrity": "sha512-oV7XU4CHYfBhk78fS7tkum+/Dpgsfi91IIDy7fjCyq2k6KB63M6gMC0YIvy+iABzmXThCRI6xpCEyVObBdWSDQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.52.0.tgz", + "integrity": "sha512-WeWnjanyEwt6+fVrSR0MYgEpUAuROxuAH516WPjUblIrClzYJj0kBbjdnbQXLpgAN8qbEuGywiQsXUVDiAoEuQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/visitor-keys": "5.52.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.52.0.tgz", + "integrity": "sha512-As3lChhrbwWQLNk2HC8Ree96hldKIqk98EYvypd3It8Q1f8d5zWyIoaZEp2va5667M4ZyE7X8UUR+azXrFl+NA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.52.0", + "@typescript-eslint/types": "5.52.0", + "@typescript-eslint/typescript-estree": "5.52.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.52.0.tgz", + "integrity": "sha512-qMwpw6SU5VHCPr99y274xhbm+PRViK/NATY6qzt+Et7+mThGuFSl/ompj2/hrBlRP/kq+BFdgagnOSgw9TB0eA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.52.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", + "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/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, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", + "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", + "dev": true, + "peer": true, + "dependencies": { + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", + "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/compiler-dom": "3.2.47", + "@vue/compiler-ssr": "3.2.47", + "@vue/reactivity-transform": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7", + "postcss": "^8.1.10", + "source-map": "^0.6.1" + } + }, + "node_modules/@vue/compiler-sfc/node_modules/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, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", + "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", + "dev": true, + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.2.47", + "@vue/shared": "3.2.47" + } + }, + "node_modules/@vue/reactivity-transform": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", + "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/parser": "^7.16.4", + "@vue/compiler-core": "3.2.47", + "@vue/shared": "3.2.47", + "estree-walker": "^2.0.2", + "magic-string": "^0.25.7" + } + }, + "node_modules/@vue/shared": { + "version": "3.2.47", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", + "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==", + "dev": true, + "peer": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "devOptional": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/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, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "devOptional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "optional": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/agentkeepalive/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "optional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "devOptional": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "engines": { + "node": "*" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacache/node_modules/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==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001452", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001452.tgz", + "integrity": "sha512-Lkp0vFjMkBB3GTpLR8zk4NwW5EdRdnitwYJHDOOKIU85x4ckYCPQ+9WlVvSVClHxVReefkUMtWZH2l9KGlD51w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/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, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/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==", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/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==" + }, + "node_modules/cli-highlight/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/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==", + "engines": { + "node": ">=10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/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, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/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==", + "devOptional": true + }, + "node_modules/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, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "devOptional": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/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, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.295", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.295.tgz", + "integrity": "sha512-lEO94zqf1bDA3aepxwnWoHUjA8sZ+2owgcSZjYQy0+uOSEclJX0VieZC+r+wLpSxUHRd6gG32znTWmr+5iGzFw==", + "dev": true + }, + "node_modules/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==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/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==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/env-cmd": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz", + "integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==", + "dev": true, + "dependencies": { + "commander": "^4.0.0", + "cross-spawn": "^7.0.0" + }, + "bin": { + "env-cmd": "bin/env-cmd.js" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/env-cmd/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "optional": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.34.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.34.0.tgz", + "integrity": "sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/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, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/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, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/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, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/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==", + "dev": true + }, + "node_modules/eslint/node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/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 + }, + "node_modules/eslint/node_modules/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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/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, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "peer": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/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==" + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/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, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/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, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "optional": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/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==", + "engines": { + "node": "*" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "optional": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/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, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "devOptional": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "optional": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "optional": true + }, + "node_modules/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==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/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, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "optional": true + }, + "node_modules/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, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "devOptional": true + }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "dev": true + }, + "node_modules/jose": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.4.tgz", + "integrity": "sha512-94FdcR8felat4vaTJyL/WVdtlWLlsnLMZP8v+A0Vru18K3bQ22vn7TtpVh3JlgBFNIlYOUlGqwp/MjRPOnIyCQ==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/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 + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/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==" + }, + "node_modules/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": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/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 + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dev": true, + "peer": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/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==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "devOptional": true + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/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==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/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==" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/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==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" + }, + "node_modules/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==", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "peer": true, + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/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, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/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==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/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 + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/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, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/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==" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/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==" + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=4" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/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, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/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, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "optional": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead", + "dev": true, + "peer": true + }, + "node_modules/sqlite3": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz", + "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/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==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tar": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", + "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^4.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", + "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/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, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/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, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "devOptional": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/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, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typeorm": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.15.tgz", + "integrity": "sha512-R4JSw8QjDP1W+ypeRz/XrCXIqubrLSnNAzJAp9EQSQIPHTv+YmUHZis8g08lOwFpuhqL9m8jkPSz8GWEKlU/ow==", + "dependencies": { + "@sqltools/formatter": "^1.2.5", + "app-root-path": "^3.1.0", + "buffer": "^6.0.3", + "chalk": "^4.1.2", + "cli-highlight": "^2.1.11", + "debug": "^4.3.4", + "dotenv": "^16.0.3", + "glob": "^8.1.0", + "mkdirp": "^2.1.3", + "reflect-metadata": "^0.1.13", + "sha.js": "^2.4.11", + "tslib": "^2.5.0", + "uuid": "^9.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "typeorm": "cli.js", + "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", + "typeorm-ts-node-esm": "cli-ts-node-esm.js" + }, + "engines": { + "node": ">= 12.9.0" + }, + "funding": { + "url": "https://opencollective.com/typeorm" + }, + "peerDependencies": { + "@google-cloud/spanner": "^5.18.0", + "@sap/hana-client": "^2.12.25", + "better-sqlite3": "^7.1.2 || ^8.0.0", + "hdb-pool": "^0.1.6", + "ioredis": "^5.0.4", + "mongodb": "^5.2.0", + "mssql": "^9.1.1", + "mysql2": "^2.2.5 || ^3.0.1", + "oracledb": "^5.1.0", + "pg": "^8.5.1", + "pg-native": "^3.0.0", + "pg-query-stream": "^4.0.0", + "redis": "^3.1.1 || ^4.0.0", + "sql.js": "^1.4.0", + "sqlite3": "^5.0.3", + "ts-node": "^10.7.0", + "typeorm-aurora-data-api-driver": "^2.0.0" + }, + "peerDependenciesMeta": { + "@google-cloud/spanner": { + "optional": true + }, + "@sap/hana-client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "hdb-pool": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mssql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "redis": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "ts-node": { + "optional": true + }, + "typeorm-aurora-data-api-driver": { + "optional": true + } + } + }, + "node_modules/typeorm/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/typeorm/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/typeorm/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/typeorm/node_modules/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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/typeorm/node_modules/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==" + }, + "node_modules/typeorm/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/typeorm/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typeorm/node_modules/mkdirp": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.3.tgz", + "integrity": "sha512-sjAkg21peAG9HS+Dkx7hlG9Ztx7HLeKnvB3NQRcu/mltCVmvkF0pisbiTSfDVYTT86XEfZrTUosLdZLStquZUw==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typeorm/node_modules/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==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typeorm/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "devOptional": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "devOptional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/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==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/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==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/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==" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } } - } } diff --git a/services/federation/package.json b/services/federation/package.json index 205eb0b3..21a4b66e 100644 --- a/services/federation/package.json +++ b/services/federation/package.json @@ -1,53 +1,53 @@ { - "name": "@crosslab/service-federation", - "dockerName": "federation-service", - "bin": { - "crosslab-federation-service": "./app/index.js" - }, - "files": [ - "app" - ], - "scripts": { - "openapi-lint": "npx --yes @redocly/cli lint ./api/openapi.yml", - "openapi-bundle": "npx --yes @redocly/cli bundle ./api/openapi.yml --output dist/openapi.json", - "watch-openapi": "npx --yes chokidar-cli 'api/**/*.yml' -c 'npm run openapi-bundle'", - "watch-rapidoc": "npx --yes browser-sync start --server --startPath 'api/rapidoc.html' --files 'dist/openapi.json'", - "build-generate-code": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service -o src/generated", - "build-compile": "tsc", - "build": "npm run build-generate-code && npm run build-compile", - "start": "node app/index.js", - "dev": "env-cmd -e development npx nodemon src/index.ts", - "format": "npx prettier src --write", - "lint": "eslint ." - }, - "author": "Johannes Nau", - "license": "UNLICENSED", - "devDependencies": { - "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", - "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", - "@trivago/prettier-plugin-sort-imports": "^4.0.0", - "@types/body-parser": "^1.19.2", - "@types/express": "^4.17.13", - "@types/node": "^17.0.41", - "@types/node-fetch": "^2.6.1", - "@typescript-eslint/eslint-plugin": "^5.51.0", - "@typescript-eslint/parser": "^5.51.0", - "env-cmd": "^10.1.0", - "eslint": "^8.34.0", - "nodemon": "^2.0.19", - "prettier": "^2.7.1", - "ts-node": "^10.9.1", - "typescript": "^4.7.3" - }, - "dependencies": { - "@crosslab/service-common": "file:../common", - "ajv-formats": "^2.1.1", - "body-parser": "^1.20.0", - "express": "^4.18.1", - "jose": "^4.10.0", - "mysql": "^2.18.1", - "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6" - } -} + "name": "@crosslab/service-federation", + "dockerName": "federation-service", + "bin": { + "crosslab-federation-service": "./app/index.js" + }, + "files": [ + "app" + ], + "scripts": { + "openapi-lint": "npx --yes @redocly/cli lint ./api/openapi.yml", + "openapi-bundle": "npx --yes @redocly/cli bundle ./api/openapi.yml --output dist/openapi.json", + "watch-openapi": "npx --yes chokidar-cli 'api/**/*.yml' -c 'npm run openapi-bundle'", + "watch-rapidoc": "npx --yes browser-sync start --server --startPath 'api/rapidoc.html' --files 'dist/openapi.json'", + "build-generate-code": "npx openapi-codegen -i dist/openapi.json -p @cross-lab-project/codegen-typescript-addon:preset:service -o src/generated", + "build-compile": "tsc", + "build": "npm run build-generate-code && npm run build-compile", + "start": "node app/index.js", + "dev": "env-cmd -e development npx nodemon src/index.ts", + "format": "npx prettier src --write", + "lint": "eslint ." + }, + "author": "Johannes Nau", + "license": "UNLICENSED", + "devDependencies": { + "@cross-lab-project/codegen-typescript-addon": "file:../../helper/crosslab-typescript-addon", + "@cross-lab-project/openapi-codegen": "file:../../helper/openapi-codegeneration", + "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/body-parser": "^1.19.2", + "@types/express": "^4.17.13", + "@types/node": "^17.0.41", + "@types/node-fetch": "^2.6.1", + "@typescript-eslint/eslint-plugin": "^5.51.0", + "@typescript-eslint/parser": "^5.51.0", + "env-cmd": "^10.1.0", + "eslint": "^8.34.0", + "nodemon": "^2.0.19", + "prettier": "^2.7.1", + "ts-node": "^10.9.1", + "typescript": "^4.7.3" + }, + "dependencies": { + "@crosslab/service-common": "file:../common", + "ajv-formats": "^2.1.1", + "body-parser": "^1.20.0", + "express": "^4.18.1", + "jose": "^4.10.0", + "mysql": "^2.18.1", + "node-fetch": "^2.6.7", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15" + } +} \ No newline at end of file diff --git a/services/update/package-lock.json b/services/update/package-lock.json index 96bc7aa7..b8ff8fdf 100644 --- a/services/update/package-lock.json +++ b/services/update/package-lock.json @@ -15,8 +15,8 @@ "ldapjs": "^2.3.3", "mysql": "^2.18.1", "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "ws": "^8.8.0" }, "bin": { @@ -43,6 +43,7 @@ } }, "../../helper/crosslab-typescript-addon": { + "name": "@cross-lab-project/codegen-typescript-addon", "dev": true, "license": "UNLICENSED", "devDependencies": { @@ -70,6 +71,7 @@ } }, "../../helper/openapi-codegeneration": { + "name": "@cross-lab-project/openapi-codegen", "dev": true, "license": "UNLICENSED", "dependencies": { @@ -78,6 +80,7 @@ "ajv-formats": "^2.1.1", "commander": "^9.4.1", "deterministic-json-schema-faker": "^0.5.0-rcv.46", + "json-schema-merge-allof": "^0.8.1", "json-schema-to-typescript": "^10.1.5", "nunjucks": "^3.2.3", "prettier": "^2.6.2", @@ -103,16 +106,21 @@ } }, "../common": { + "name": "@crosslab/service-common", "license": "UNLICENSED", "dependencies": { "jose": "^4.11.1" }, "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.0.0", + "@types/mocha": "^10.0.1", "@types/node": "^18.11.18", "@typescript-eslint/eslint-plugin": "^5.51.0", "@typescript-eslint/parser": "^5.51.0", "eslint": "^8.34.0", + "mocha": "^10.2.0", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "typescript": "^4.9.4" } }, @@ -2367,18 +2375,6 @@ "node": ">= 8" } }, - "node_modules/date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -4839,11 +4835,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -5064,9 +5055,9 @@ "peer": true }, "node_modules/sqlite3": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.4.tgz", - "integrity": "sha512-i0UlWAzPlzX3B5XP2cYuhWQJsTtlMD6obOa1PgeEQ4DHEXUuyJkgv50I3isqZAP5oFc2T8OFvakmDh2W6I+YpA==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.6.tgz", + "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", "hasInstallScript": true, "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", @@ -5390,26 +5381,23 @@ } }, "node_modules/typeorm": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", - "integrity": "sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==", + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.15.tgz", + "integrity": "sha512-R4JSw8QjDP1W+ypeRz/XrCXIqubrLSnNAzJAp9EQSQIPHTv+YmUHZis8g08lOwFpuhqL9m8jkPSz8GWEKlU/ow==", "dependencies": { "@sqltools/formatter": "^1.2.5", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "chalk": "^4.1.2", "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", "debug": "^4.3.4", "dotenv": "^16.0.3", "glob": "^8.1.0", - "js-yaml": "^4.1.0", "mkdirp": "^2.1.3", "reflect-metadata": "^0.1.13", "sha.js": "^2.4.11", "tslib": "^2.5.0", "uuid": "^9.0.0", - "xml2js": "^0.4.23", "yargs": "^17.6.2" }, "bin": { @@ -5429,8 +5417,8 @@ "better-sqlite3": "^7.1.2 || ^8.0.0", "hdb-pool": "^0.1.6", "ioredis": "^5.0.4", - "mongodb": "^3.6.0", - "mssql": "^7.3.0", + "mongodb": "^5.2.0", + "mssql": "^9.1.1", "mysql2": "^2.2.5 || ^3.0.1", "oracledb": "^5.1.0", "pg": "^8.5.1", @@ -5510,11 +5498,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/typeorm/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, "node_modules/typeorm/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -5580,17 +5563,6 @@ "node": ">=8" } }, - "node_modules/typeorm/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/typeorm/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -5910,26 +5882,6 @@ } } }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/services/update/package.json b/services/update/package.json index 09b46347..fe9525f1 100644 --- a/services/update/package.json +++ b/services/update/package.json @@ -51,8 +51,8 @@ "ldapjs": "^2.3.3", "mysql": "^2.18.1", "node-fetch": "^2.6.7", - "sqlite3": "^5.0.8", - "typeorm": "^0.3.6", + "sqlite3": "^5.1.6", + "typeorm": "^0.3.15", "ws": "^8.8.0" } -} +} \ No newline at end of file From 2ab3f9d97c6ee27131e06c0f4801acff7261308f Mon Sep 17 00:00:00 2001 From: Pierre Helbing Date: Fri, 28 Apr 2023 09:19:51 +0000 Subject: [PATCH 33/33] Address requested changes (except prettierrc) - reset settings.json to original state - edit function in soa client for better readability --- .vscode/settings.json | 2 +- clients/.vscode/settings.json | 1 + clients/api/.vscode/settings.json | 1 + clients/api/js/.vscode/settings.json | 1 + clients/api/python/.vscode/settings.json | 1 + clients/soa/.vscode/settings.json | 1 + clients/soa/js/.vscode/settings.json | 1 + clients/soa/js/src/deviceHandler.ts | 70 ++++++++++--------- clients/soa/python/.vscode/settings.json | 1 + clients/soa_services/.vscode/settings.json | 1 + .../.vscode/settings.json | 1 + .../js/.vscode/settings.json | 1 + .../python/.vscode/settings.json | 1 + .../soa_services/file/.vscode/settings.json | 1 + .../file/js/.vscode/settings.json | 1 + .../file/python/.vscode/settings.json | 1 + .../message/.vscode/settings.json | 1 + .../message/js/.vscode/settings.json | 1 + .../message/python/.vscode/settings.json | 1 + .../soa_services/webcam/.vscode/settings.json | 1 + .../webcam/js/.vscode/settings.json | 1 + .../webcam/python/.vscode/settings.json | 1 + helper/.vscode/settings.json | 1 + .../.vscode/settings.json | 1 + helper/dummy-device/.vscode/settings.json | 1 + helper/dummy-device/js/.vscode/settings.json | 1 + .../dummy-device/python/.vscode/settings.json | 1 + .../.vscode/settings.json | 1 + .../python-test-helper/.vscode/settings.json | 1 + helper/tsdoc-theme/.vscode/settings.json | 1 + integration-test/.vscode/settings.json | 1 + services/.vscode/settings.json | 1 + services/auth/.vscode/settings.json | 1 + services/booking/.vscode/settings.json | 1 + services/common/.vscode/settings.json | 1 + services/device/.vscode/settings.json | 1 + services/experiment/.vscode/settings.json | 1 + services/federation/.vscode/settings.json | 1 + services/gateway/.vscode/settings.json | 1 + services/openapi/.vscode/settings.json | 1 + services/update/.vscode/settings.json | 1 + 41 files changed, 76 insertions(+), 35 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b0a53998..37747357 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,7 +13,7 @@ "**/__pycache__": true, "**/*.egg-info": true, "**/build": true, - // "**/lib": true, + "**/lib": true, "**/app": true, "**/venv": true, "**/.packages": true, diff --git a/clients/.vscode/settings.json b/clients/.vscode/settings.json index afc12f8d..6c57a59b 100644 --- a/clients/.vscode/settings.json +++ b/clients/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, "api/.vscode": true, diff --git a/clients/api/.vscode/settings.json b/clients/api/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/api/.vscode/settings.json +++ b/clients/api/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/api/js/.vscode/settings.json b/clients/api/js/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/api/js/.vscode/settings.json +++ b/clients/api/js/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/api/python/.vscode/settings.json b/clients/api/python/.vscode/settings.json index 6ff7291e..8f7703e3 100644 --- a/clients/api/python/.vscode/settings.json +++ b/clients/api/python/.vscode/settings.json @@ -24,6 +24,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa/.vscode/settings.json b/clients/soa/.vscode/settings.json index 604ee547..25e84362 100644 --- a/clients/soa/.vscode/settings.json +++ b/clients/soa/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, "./clients/soa_services/.vscode": true, diff --git a/clients/soa/js/.vscode/settings.json b/clients/soa/js/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/soa/js/.vscode/settings.json +++ b/clients/soa/js/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa/js/src/deviceHandler.ts b/clients/soa/js/src/deviceHandler.ts index 604d3d9e..fe7512d4 100644 --- a/clients/soa/js/src/deviceHandler.ts +++ b/clients/soa/js/src/deviceHandler.ts @@ -23,40 +23,27 @@ export class DeviceHandler extends TypedEmitter { async connect(connectOptions: {endpoint: string; id: string; token: string}) { this.ws = new WebSocket(connectOptions.endpoint); - const p = new Promise((resolve, reject) => { - this.ws.onopen = () => { - this.ws.onmessage = authenticationEvent => { - const authenticationMessage = JSON.parse(authenticationEvent.data as string) - if (authenticationMessage.messageType === "authenticate") { - if (authenticationMessage.authenticated) { - resolve() - } - else reject("Authentication failed") - } else { - reject(`Èxpected message with messageType 'authenticate', received '${authenticationMessage.messageType}'`) - } - this.ws.onmessage = event => { - const message = JSON.parse(event.data as string); - - if (isCommandMessage(message)) { - if (isCreatePeerConnectionMessage(message)) { - this.handleCreatePeerConnectionMessage(message); - } - } - if (isSignalingMessage(message)) { - this.handleSignalingMessage(message); - } - }; + this.ws.onopen = () => { + this.ws.send( + JSON.stringify({ + messageType: 'authenticate', + deviceUrl: connectOptions.id, + token: connectOptions.token, + }), + ); + }; + + const p = new Promise((resolve, reject) => { + this.ws.onmessage = authenticationEvent => { + const authenticationMessage = JSON.parse(authenticationEvent.data as string); + if (authenticationMessage.messageType === 'authenticate') { + if (authenticationMessage.authenticated) { + resolve(); + } else reject('Authentication failed'); + } else { + reject(`Èxpected message with messageType 'authenticate', received '${authenticationMessage.messageType}'`); } - - this.ws.send( - JSON.stringify({ - messageType: 'authenticate', - deviceUrl: connectOptions.id, - token: connectOptions.token, - }), - ); }; }); @@ -69,6 +56,19 @@ export class DeviceHandler extends TypedEmitter { }; await p; + + this.ws.onmessage = event => { + const message = JSON.parse(event.data as string); + + if (isCommandMessage(message)) { + if (isCreatePeerConnectionMessage(message)) { + this.handleCreatePeerConnectionMessage(message); + } + } + if (isSignalingMessage(message)) { + this.handleSignalingMessage(message); + } + }; } addService(service: Service) { @@ -80,9 +80,11 @@ export class DeviceHandler extends TypedEmitter { throw Error('Can not create a connection. Connection Id is already present'); } console.log('creating connection', message); - const connection = new WebRTCPeerConnection({}/*{ + const connection = new WebRTCPeerConnection( + {} /*{ iceServers: [{urls: 'stun:stun.goldi-labs.de:3478'}, {urls: 'turn:turn.goldi-labs.de:3478', username: 'goldi', credential: 'goldi'}], - }*/); + }*/, + ); connection.tiebreaker = message.tiebreaker; this.connections.set(message.connectionUrl, connection); for (const serviceConfig of message.services) { diff --git a/clients/soa/python/.vscode/settings.json b/clients/soa/python/.vscode/settings.json index 04477f7d..2aadde0b 100644 --- a/clients/soa/python/.vscode/settings.json +++ b/clients/soa/python/.vscode/settings.json @@ -24,6 +24,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/.vscode/settings.json b/clients/soa_services/.vscode/settings.json index 01683554..5046f1b8 100644 --- a/clients/soa_services/.vscode/settings.json +++ b/clients/soa_services/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, "electricalConnection/.vscode": true, diff --git a/clients/soa_services/electricalConnection/.vscode/settings.json b/clients/soa_services/electricalConnection/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/soa_services/electricalConnection/.vscode/settings.json +++ b/clients/soa_services/electricalConnection/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/electricalConnection/js/.vscode/settings.json b/clients/soa_services/electricalConnection/js/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/soa_services/electricalConnection/js/.vscode/settings.json +++ b/clients/soa_services/electricalConnection/js/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/electricalConnection/python/.vscode/settings.json b/clients/soa_services/electricalConnection/python/.vscode/settings.json index 6ff7291e..8f7703e3 100644 --- a/clients/soa_services/electricalConnection/python/.vscode/settings.json +++ b/clients/soa_services/electricalConnection/python/.vscode/settings.json @@ -24,6 +24,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/file/.vscode/settings.json b/clients/soa_services/file/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/soa_services/file/.vscode/settings.json +++ b/clients/soa_services/file/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/file/js/.vscode/settings.json b/clients/soa_services/file/js/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/soa_services/file/js/.vscode/settings.json +++ b/clients/soa_services/file/js/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/file/python/.vscode/settings.json b/clients/soa_services/file/python/.vscode/settings.json index 6ff7291e..8f7703e3 100644 --- a/clients/soa_services/file/python/.vscode/settings.json +++ b/clients/soa_services/file/python/.vscode/settings.json @@ -24,6 +24,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/message/.vscode/settings.json b/clients/soa_services/message/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/soa_services/message/.vscode/settings.json +++ b/clients/soa_services/message/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/message/js/.vscode/settings.json b/clients/soa_services/message/js/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/soa_services/message/js/.vscode/settings.json +++ b/clients/soa_services/message/js/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/message/python/.vscode/settings.json b/clients/soa_services/message/python/.vscode/settings.json index 6ff7291e..8f7703e3 100644 --- a/clients/soa_services/message/python/.vscode/settings.json +++ b/clients/soa_services/message/python/.vscode/settings.json @@ -24,6 +24,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/webcam/.vscode/settings.json b/clients/soa_services/webcam/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/soa_services/webcam/.vscode/settings.json +++ b/clients/soa_services/webcam/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/webcam/js/.vscode/settings.json b/clients/soa_services/webcam/js/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/clients/soa_services/webcam/js/.vscode/settings.json +++ b/clients/soa_services/webcam/js/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/clients/soa_services/webcam/python/.vscode/settings.json b/clients/soa_services/webcam/python/.vscode/settings.json index 6ff7291e..8f7703e3 100644 --- a/clients/soa_services/webcam/python/.vscode/settings.json +++ b/clients/soa_services/webcam/python/.vscode/settings.json @@ -24,6 +24,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/helper/.vscode/settings.json b/helper/.vscode/settings.json index 88acdb2d..194559cc 100644 --- a/helper/.vscode/settings.json +++ b/helper/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, "dummy-device/.vscode": true, diff --git a/helper/crosslab-typescript-addon/.vscode/settings.json b/helper/crosslab-typescript-addon/.vscode/settings.json index dcde8ba1..1a2d8d88 100644 --- a/helper/crosslab-typescript-addon/.vscode/settings.json +++ b/helper/crosslab-typescript-addon/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/helper/dummy-device/.vscode/settings.json b/helper/dummy-device/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/helper/dummy-device/.vscode/settings.json +++ b/helper/dummy-device/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/helper/dummy-device/js/.vscode/settings.json b/helper/dummy-device/js/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/helper/dummy-device/js/.vscode/settings.json +++ b/helper/dummy-device/js/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/helper/dummy-device/python/.vscode/settings.json b/helper/dummy-device/python/.vscode/settings.json index d7d9073d..788f0ff4 100644 --- a/helper/dummy-device/python/.vscode/settings.json +++ b/helper/dummy-device/python/.vscode/settings.json @@ -19,6 +19,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/helper/openapi-codegeneration/.vscode/settings.json b/helper/openapi-codegeneration/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/helper/openapi-codegeneration/.vscode/settings.json +++ b/helper/openapi-codegeneration/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/helper/python-test-helper/.vscode/settings.json b/helper/python-test-helper/.vscode/settings.json index 6ff7291e..8f7703e3 100644 --- a/helper/python-test-helper/.vscode/settings.json +++ b/helper/python-test-helper/.vscode/settings.json @@ -24,6 +24,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/helper/tsdoc-theme/.vscode/settings.json b/helper/tsdoc-theme/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/helper/tsdoc-theme/.vscode/settings.json +++ b/helper/tsdoc-theme/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/integration-test/.vscode/settings.json b/integration-test/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/integration-test/.vscode/settings.json +++ b/integration-test/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/.vscode/settings.json b/services/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/services/.vscode/settings.json +++ b/services/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/auth/.vscode/settings.json b/services/auth/.vscode/settings.json index ade2a593..fed86ff6 100644 --- a/services/auth/.vscode/settings.json +++ b/services/auth/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/booking/.vscode/settings.json b/services/booking/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/services/booking/.vscode/settings.json +++ b/services/booking/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/common/.vscode/settings.json b/services/common/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/services/common/.vscode/settings.json +++ b/services/common/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/device/.vscode/settings.json b/services/device/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/services/device/.vscode/settings.json +++ b/services/device/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/experiment/.vscode/settings.json b/services/experiment/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/services/experiment/.vscode/settings.json +++ b/services/experiment/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/federation/.vscode/settings.json b/services/federation/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/services/federation/.vscode/settings.json +++ b/services/federation/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/gateway/.vscode/settings.json b/services/gateway/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/services/gateway/.vscode/settings.json +++ b/services/gateway/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/openapi/.vscode/settings.json b/services/openapi/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/services/openapi/.vscode/settings.json +++ b/services/openapi/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated diff --git a/services/update/.vscode/settings.json b/services/update/.vscode/settings.json index e5aba7fc..f90817be 100644 --- a/services/update/.vscode/settings.json +++ b/services/update/.vscode/settings.json @@ -9,6 +9,7 @@ "**/__pycache__": true, "**/app": true, "**/build": true, + "**/lib": true, "**/node_modules": true, "**/venv": true, //end generated