From 5e1fc1ad11395272fa31e99091a588d1f3a2c3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20M?= Date: Tue, 4 Jul 2023 16:02:44 +0200 Subject: [PATCH] feat: upload module (#486) * feat: wip upload module * feat: local storage and serve local images * feat: protect against injections * feat: server local and s3 files * fix: use storage location when serving local files * feat: cross field env validation --- .gitignore | 2 +- server/.env.example | 3 + server/.gitignore | 5 +- server/package.json | 12 + server/src/app.module.ts | 2 + server/src/constants/settings/index.ts | 9 + .../settings/interfaces/settings.interface.ts | 12 + server/src/core/auth/auth.module.ts | 14 +- .../core/auth/services/token.service.spec.ts | 4 +- .../src/core/auth/services/token.service.ts | 24 +- .../auth/strategies/google.auth.strategy.ts | 10 +- .../core/auth/strategies/jwt.auth.strategy.ts | 6 +- server/src/core/core.module.ts | 2 + .../file/controllers/file.controller.spec.ts | 25 + .../core/file/controllers/file.controller.ts | 30 + server/src/core/file/file.module.ts | 12 + server/src/core/file/file.utils.ts | 46 + .../file/interfaces/file-folder.interface.ts | 9 + .../resolvers/file-upload.resolver.spec.ts | 25 + .../file/resolvers/file-upload.resolver.ts | 60 + .../file/services/file-upload.service.spec.ts | 35 + .../core/file/services/file-upload.service.ts | 135 ++ .../core/file/services/file.service.spec.ts | 30 + server/src/core/file/services/file.service.ts | 55 + .../decorators/is-aws-region.decorator.ts | 26 + .../decorators/is-duration.decorator.ts | 27 + .../environment.module-definition.ts | 8 + .../environment/environment.module.ts | 19 + .../environment/environment.service.spec.ts | 25 + .../environment/environment.service.ts | 66 + .../environment/environment.validation.ts | 77 + .../interfaces/aws-region.interface.ts | 1 + .../interfaces/storage.interface.ts | 4 + .../src/integrations/integrations.module.ts | 69 + .../local-storage/interfaces/index.ts | 1 + .../interfaces/local-storage.interface.ts | 3 + .../local-storage.module-definition.ts | 9 + .../local-storage/local-storage.module.ts | 10 + .../local-storage.service.spec.ts | 25 + .../local-storage/local-storage.service.ts | 35 + .../s3-storage/interfaces/index.ts | 1 + .../interfaces/s3-storage-module.interface.ts | 5 + .../s3-storage.module-definition.ts | 9 + .../s3-storage/s3-storage.module.ts | 10 + .../s3-storage/s3-storage.service.spec.ts | 25 + .../s3-storage/s3-storage.service.ts | 86 + server/src/main.ts | 4 + server/src/utils/camel-case.ts | 26 + server/src/utils/image.ts | 21 + server/src/utils/kebab-case.ts | 26 + server/src/utils/stream-to-buffer.ts | 11 + server/yarn.lock | 1500 ++++++++++++++++- 52 files changed, 2632 insertions(+), 64 deletions(-) create mode 100644 server/src/constants/settings/index.ts create mode 100644 server/src/constants/settings/interfaces/settings.interface.ts create mode 100644 server/src/core/file/controllers/file.controller.spec.ts create mode 100644 server/src/core/file/controllers/file.controller.ts create mode 100644 server/src/core/file/file.module.ts create mode 100644 server/src/core/file/file.utils.ts create mode 100644 server/src/core/file/interfaces/file-folder.interface.ts create mode 100644 server/src/core/file/resolvers/file-upload.resolver.spec.ts create mode 100644 server/src/core/file/resolvers/file-upload.resolver.ts create mode 100644 server/src/core/file/services/file-upload.service.spec.ts create mode 100644 server/src/core/file/services/file-upload.service.ts create mode 100644 server/src/core/file/services/file.service.spec.ts create mode 100644 server/src/core/file/services/file.service.ts create mode 100644 server/src/integrations/environment/decorators/is-aws-region.decorator.ts create mode 100644 server/src/integrations/environment/decorators/is-duration.decorator.ts create mode 100644 server/src/integrations/environment/environment.module-definition.ts create mode 100644 server/src/integrations/environment/environment.module.ts create mode 100644 server/src/integrations/environment/environment.service.spec.ts create mode 100644 server/src/integrations/environment/environment.service.ts create mode 100644 server/src/integrations/environment/environment.validation.ts create mode 100644 server/src/integrations/environment/interfaces/aws-region.interface.ts create mode 100644 server/src/integrations/environment/interfaces/storage.interface.ts create mode 100644 server/src/integrations/integrations.module.ts create mode 100644 server/src/integrations/local-storage/interfaces/index.ts create mode 100644 server/src/integrations/local-storage/interfaces/local-storage.interface.ts create mode 100644 server/src/integrations/local-storage/local-storage.module-definition.ts create mode 100644 server/src/integrations/local-storage/local-storage.module.ts create mode 100644 server/src/integrations/local-storage/local-storage.service.spec.ts create mode 100644 server/src/integrations/local-storage/local-storage.service.ts create mode 100644 server/src/integrations/s3-storage/interfaces/index.ts create mode 100644 server/src/integrations/s3-storage/interfaces/s3-storage-module.interface.ts create mode 100644 server/src/integrations/s3-storage/s3-storage.module-definition.ts create mode 100644 server/src/integrations/s3-storage/s3-storage.module.ts create mode 100644 server/src/integrations/s3-storage/s3-storage.service.spec.ts create mode 100644 server/src/integrations/s3-storage/s3-storage.service.ts create mode 100644 server/src/utils/camel-case.ts create mode 100644 server/src/utils/image.ts create mode 100644 server/src/utils/kebab-case.ts create mode 100644 server/src/utils/stream-to-buffer.ts diff --git a/.gitignore b/.gitignore index 75c8b73ca8b8..0e77b13e13fe 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ .DS_Store node_modules/ # yarn is the recommended package manager across the project -.package-lock.json \ No newline at end of file +.package-lock.json diff --git a/server/.env.example b/server/.env.example index 3962b151e7fe..69dd8ffdb559 100644 --- a/server/.env.example +++ b/server/.env.example @@ -9,3 +9,6 @@ REFRESH_TOKEN_SECRET=secret_refresh_token REFRESH_TOKEN_EXPIRES_IN=90d PG_DATABASE_URL=postgres://postgres:postgrespassword@postgres:5432/default?connection_limit=1 FRONT_AUTH_CALLBACK_URL=http://localhost:3001/auth/callback +STORAGE_TYPE=local +STORAGE_REGION=eu-west-1 +STORAGE_LOCATION=.local-storage diff --git a/server/.gitignore b/server/.gitignore index f505884128a6..f1b84825d143 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -32,4 +32,7 @@ lerna-debug.log* !.vscode/settings.json !.vscode/inbox.json !.vscode/launch.json -!.vscode/extensions.json \ No newline at end of file +!.vscode/extensions.json + +# Local storage +.local-storage diff --git a/server/package.json b/server/package.json index db44a550f7ca..678b4fcf4265 100644 --- a/server/package.json +++ b/server/package.json @@ -28,6 +28,8 @@ }, "dependencies": { "@apollo/server": "^4.7.3", + "@aws-sdk/client-s3": "^3.363.0", + "@aws-sdk/credential-providers": "^3.363.0", "@casl/ability": "^6.5.0", "@casl/prisma": "^1.4.0", "@nestjs/apollo": "^11.0.5", @@ -42,6 +44,7 @@ "@nestjs/terminus": "^9.2.2", "@paljs/plugins": "^5.3.3", "@prisma/client": "^4.13.0", + "@types/lodash.camelcase": "^4.3.7", "add": "^2.0.6", "apollo-server-express": "^3.12.0", "axios": "^1.4.0", @@ -51,8 +54,12 @@ "date-fns": "^2.30.0", "graphql": "^16.6.0", "graphql-type-json": "^0.3.2", + "graphql-upload": "^13.0.0", "jest-mock-extended": "^3.0.4", "jsonwebtoken": "^9.0.0", + "lodash.camelcase": "^4.3.0", + "lodash.isobject": "^3.0.2", + "lodash.kebabcase": "^4.1.1", "ms": "^2.1.3", "passport": "^0.6.0", "passport-google-oauth20": "^2.0.0", @@ -61,6 +68,8 @@ "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0", + "sharp": "^0.32.1", + "type-fest": "^3.12.0", "uuid": "^9.0.0", "yarn": "^1.22.19" }, @@ -71,7 +80,10 @@ "@types/bcrypt": "^5.0.0", "@types/date-fns": "^2.6.0", "@types/express": "^4.17.13", + "@types/graphql-upload": "^8.0.12", "@types/jest": "28.1.8", + "@types/lodash.isobject": "^3.0.7", + "@types/lodash.kebabcase": "^4.1.7", "@types/ms": "^0.7.31", "@types/node": "^16.0.0", "@types/passport-google-oauth20": "^2.0.11", diff --git a/server/src/app.module.ts b/server/src/app.module.ts index 8ef5273c331f..de01d3b4bb1d 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -4,6 +4,7 @@ import { AppService } from './app.service'; import { ConfigModule } from '@nestjs/config'; import { CoreModule } from './core/core.module'; +import { IntegrationsModule } from './integrations/integrations.module'; import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'; import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default'; import { GraphQLError } from 'graphql'; @@ -33,6 +34,7 @@ import GraphQLJSON from 'graphql-type-json'; HealthModule, AbilityModule, CoreModule, + IntegrationsModule, ], providers: [AppService], }) diff --git a/server/src/constants/settings/index.ts b/server/src/constants/settings/index.ts new file mode 100644 index 000000000000..bcea0985b7b9 --- /dev/null +++ b/server/src/constants/settings/index.ts @@ -0,0 +1,9 @@ +import { Settings } from './interfaces/settings.interface'; + +export const settings: Settings = { + storage: { + imageCropSizes: { + profilePicture: ['original'], + }, + }, +}; diff --git a/server/src/constants/settings/interfaces/settings.interface.ts b/server/src/constants/settings/interfaces/settings.interface.ts new file mode 100644 index 000000000000..f1caa0fb5186 --- /dev/null +++ b/server/src/constants/settings/interfaces/settings.interface.ts @@ -0,0 +1,12 @@ +import { FileFolder } from 'src/core/file/interfaces/file-folder.interface'; +import { ShortCropSize } from 'src/utils/image'; + +type ValueOfFileFolder = `${FileFolder}`; + +export interface Settings { + storage: { + imageCropSizes: { + [key in ValueOfFileFolder]: ShortCropSize[]; + }; + }; +} diff --git a/server/src/core/auth/auth.module.ts b/server/src/core/auth/auth.module.ts index 91e116778419..477ba3676d18 100644 --- a/server/src/core/auth/auth.module.ts +++ b/server/src/core/auth/auth.module.ts @@ -1,6 +1,5 @@ import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; -import { ConfigModule, ConfigService } from '@nestjs/config'; import { JwtAuthStrategy } from './strategies/jwt.auth.strategy'; import { AuthService } from './services/auth.service'; import { GoogleAuthController } from './controllers/google-auth.controller'; @@ -8,25 +7,24 @@ import { GoogleStrategy } from './strategies/google.auth.strategy'; import { PrismaService } from 'src/database/prisma.service'; import { UserModule } from '../user/user.module'; import { VerifyAuthController } from './controllers/verify-auth.controller'; - import { TokenService } from './services/token.service'; import { AuthResolver } from './auth.resolver'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; const jwtModule = JwtModule.registerAsync({ - useFactory: async (configService: ConfigService) => { + useFactory: async (environmentService: EnvironmentService) => { return { - secret: configService.get('ACCESS_TOKEN_SECRET'), + secret: environmentService.getAccessTokenSecret(), signOptions: { - expiresIn: configService.get('ACCESS_TOKEN_EXPIRES_IN'), + expiresIn: environmentService.getAccessTokenExpiresIn(), }, }; }, - imports: [ConfigModule.forRoot({})], - inject: [ConfigService], + inject: [EnvironmentService], }); @Module({ - imports: [jwtModule, ConfigModule.forRoot({}), UserModule], + imports: [jwtModule, UserModule], controllers: [GoogleAuthController, VerifyAuthController], providers: [ AuthService, diff --git a/server/src/core/auth/services/token.service.spec.ts b/server/src/core/auth/services/token.service.spec.ts index a17a9ff6fee0..78c706fa3aa9 100644 --- a/server/src/core/auth/services/token.service.spec.ts +++ b/server/src/core/auth/services/token.service.spec.ts @@ -3,7 +3,7 @@ import { TokenService } from './token.service'; import { PrismaService } from 'src/database/prisma.service'; import { prismaMock } from 'src/database/client-mock/jest-prisma-singleton'; import { JwtService } from '@nestjs/jwt'; -import { ConfigService } from '@nestjs/config'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; describe('TokenService', () => { let service: TokenService; @@ -17,7 +17,7 @@ describe('TokenService', () => { useValue: {}, }, { - provide: ConfigService, + provide: EnvironmentService, useValue: {}, }, { diff --git a/server/src/core/auth/services/token.service.ts b/server/src/core/auth/services/token.service.ts index 579b20ac02ad..e01b9d3bd5b6 100644 --- a/server/src/core/auth/services/token.service.ts +++ b/server/src/core/auth/services/token.service.ts @@ -8,24 +8,24 @@ import { } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { JwtPayload } from '../strategies/jwt.auth.strategy'; -import { ConfigService } from '@nestjs/config'; import { PrismaService } from 'src/database/prisma.service'; import { assert } from 'src/utils/assert'; import { addMilliseconds } from 'date-fns'; import ms from 'ms'; import { AuthToken } from '../dto/token.entity'; import { TokenExpiredError } from 'jsonwebtoken'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; @Injectable() export class TokenService { constructor( private readonly jwtService: JwtService, - private readonly configService: ConfigService, + private readonly environmentService: EnvironmentService, private readonly prismaService: PrismaService, ) {} async generateAccessToken(userId: string): Promise { - const expiresIn = this.configService.get('ACCESS_TOKEN_EXPIRES_IN'); + const expiresIn = this.environmentService.getAccessTokenExpiresIn(); assert(expiresIn, '', InternalServerErrorException); const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn)); @@ -56,10 +56,8 @@ export class TokenService { } async generateRefreshToken(userId: string): Promise { - const secret = this.configService.get('REFRESH_TOKEN_SECRET'); - const expiresIn = this.configService.get( - 'REFRESH_TOKEN_EXPIRES_IN', - ); + const secret = this.environmentService.getRefreshTokenSecret(); + const expiresIn = this.environmentService.getRefreshTokenExpiresIn(); assert(expiresIn, '', InternalServerErrorException); const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn)); @@ -87,8 +85,8 @@ export class TokenService { } async generateLoginToken(email: string): Promise { - const secret = this.configService.get('LOGIN_TOKEN_SECRET'); - const expiresIn = this.configService.get('LOGIN_TOKEN_EXPIRES_IN'); + const secret = this.environmentService.getLoginTokenSecret(); + const expiresIn = this.environmentService.getLoginTokenExpiresIn(); assert(expiresIn, '', InternalServerErrorException); const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn)); const jwtPayload = { @@ -105,7 +103,7 @@ export class TokenService { } async verifyLoginToken(loginToken: string): Promise { - const loginTokenSecret = this.configService.get('LOGIN_TOKEN_SECRET'); + const loginTokenSecret = this.environmentService.getLoginTokenSecret(); const payload = await this.verifyJwt(loginToken, loginTokenSecret); @@ -113,7 +111,7 @@ export class TokenService { } async verifyRefreshToken(refreshToken: string) { - const secret = this.configService.get('REFRESH_TOKEN_SECRET'); + const secret = this.environmentService.getRefreshTokenSecret(); const jwtPayload = await this.verifyJwt(refreshToken, secret); assert( @@ -191,9 +189,7 @@ export class TokenService { } computeRedirectURI(loginToken: string): string { - return `${this.configService.get( - 'FRONT_AUTH_CALLBACK_URL', - )}?loginToken=${loginToken}`; + return `${this.environmentService.getFrontAuthCallbackUrl()}?loginToken=${loginToken}`; } async verifyJwt(token: string, secret?: string) { diff --git a/server/src/core/auth/strategies/google.auth.strategy.ts b/server/src/core/auth/strategies/google.auth.strategy.ts index 80a9da68e8f6..a14f52f7ad4f 100644 --- a/server/src/core/auth/strategies/google.auth.strategy.ts +++ b/server/src/core/auth/strategies/google.auth.strategy.ts @@ -2,8 +2,8 @@ import { PassportStrategy } from '@nestjs/passport'; import { Strategy, VerifyCallback } from 'passport-google-oauth20'; import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; import { Request } from 'express'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; export type GoogleRequest = Request & { user: { @@ -15,11 +15,11 @@ export type GoogleRequest = Request & { @Injectable() export class GoogleStrategy extends PassportStrategy(Strategy, 'google') { - constructor(configService: ConfigService) { + constructor(environmentService: EnvironmentService) { super({ - clientID: configService.get('AUTH_GOOGLE_CLIENT_ID'), - clientSecret: configService.get('AUTH_GOOGLE_CLIENT_SECRET'), - callbackURL: configService.get('AUTH_GOOGLE_CALLBACK_URL'), + clientID: environmentService.getAuthGoogleClientId(), + clientSecret: environmentService.getAuthGoogleClientSecret(), + callbackURL: environmentService.getAuthGoogleCallbackUrl(), scope: ['email', 'profile'], }); } diff --git a/server/src/core/auth/strategies/jwt.auth.strategy.ts b/server/src/core/auth/strategies/jwt.auth.strategy.ts index 903ac9da6bec..5934a6515e9f 100644 --- a/server/src/core/auth/strategies/jwt.auth.strategy.ts +++ b/server/src/core/auth/strategies/jwt.auth.strategy.ts @@ -1,9 +1,9 @@ import { Strategy, ExtractJwt } from 'passport-jwt'; import { PassportStrategy } from '@nestjs/passport'; import { Injectable, UnauthorizedException } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; import { PrismaService } from 'src/database/prisma.service'; import { User, Workspace } from '@prisma/client'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; export type JwtPayload = { sub: string; workspaceId: string }; export type PassportUser = { user: User; workspace: Workspace }; @@ -11,13 +11,13 @@ export type PassportUser = { user: User; workspace: Workspace }; @Injectable() export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') { constructor( - private readonly configService: ConfigService, + private readonly environmentService: EnvironmentService, private readonly prismaService: PrismaService, ) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, - secretOrKey: configService.get('ACCESS_TOKEN_SECRET'), + secretOrKey: environmentService.getAccessTokenSecret(), }); } diff --git a/server/src/core/core.module.ts b/server/src/core/core.module.ts index e33b0d833ac1..16b4b031c409 100644 --- a/server/src/core/core.module.ts +++ b/server/src/core/core.module.ts @@ -7,6 +7,7 @@ import { PipelineModule } from './pipeline/pipeline.module'; import { AuthModule } from './auth/auth.module'; import { WorkspaceModule } from './workspace/workspace.module'; import { AnalyticsModule } from './analytics/analytics.module'; +import { FileModule } from './file/file.module'; @Module({ imports: [ @@ -18,6 +19,7 @@ import { AnalyticsModule } from './analytics/analytics.module'; PipelineModule, WorkspaceModule, AnalyticsModule, + FileModule, ], exports: [ AuthModule, diff --git a/server/src/core/file/controllers/file.controller.spec.ts b/server/src/core/file/controllers/file.controller.spec.ts new file mode 100644 index 000000000000..20bff93c9c9b --- /dev/null +++ b/server/src/core/file/controllers/file.controller.spec.ts @@ -0,0 +1,25 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { FileController } from './file.controller'; +import { FileService } from '../services/file.service'; + +describe('FileController', () => { + let controller: FileController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [FileController], + providers: [ + { + provide: FileService, + useValue: {}, + }, + ], + }).compile(); + + controller = module.get(FileController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/server/src/core/file/controllers/file.controller.ts b/server/src/core/file/controllers/file.controller.ts new file mode 100644 index 000000000000..b50004af7a2e --- /dev/null +++ b/server/src/core/file/controllers/file.controller.ts @@ -0,0 +1,30 @@ +import { Controller, Get, Param, Res, UseGuards } from '@nestjs/common'; +import { Response } from 'express'; +import { checkFilePath, checkFilename } from '../file.utils'; +import { FileService } from '../services/file.service'; +import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; + +@UseGuards(JwtAuthGuard) +@Controller('files') +export class FileController { + constructor(private readonly fileService: FileService) {} + /** + * Serve files from local storage + * We recommend using an s3 bucket for production + */ + @Get('*/:filename') + async getFile(@Param() params: string[], @Res() res: Response) { + const folderPath = checkFilePath(params[0]); + const filename = checkFilename(params['filename']); + const fileStream = await this.fileService.getFileStream( + folderPath, + filename, + ); + + fileStream.on('error', () => { + res.status(404).send({ error: 'File not found' }); + }); + + fileStream.pipe(res); + } +} diff --git a/server/src/core/file/file.module.ts b/server/src/core/file/file.module.ts new file mode 100644 index 000000000000..1595393ae3b8 --- /dev/null +++ b/server/src/core/file/file.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { FileService } from './services/file.service'; +import { FileUploadService } from './services/file-upload.service'; +import { FileUploadResolver } from './resolvers/file-upload.resolver'; +import { FileController } from './controllers/file.controller'; + +@Module({ + providers: [FileService, FileUploadService, FileUploadResolver], + exports: [FileService, FileUploadService], + controllers: [FileController], +}) +export class FileModule {} diff --git a/server/src/core/file/file.utils.ts b/server/src/core/file/file.utils.ts new file mode 100644 index 000000000000..904525f6fce4 --- /dev/null +++ b/server/src/core/file/file.utils.ts @@ -0,0 +1,46 @@ +import { kebabCase } from 'src/utils/kebab-case'; +import { FileFolder } from './interfaces/file-folder.interface'; +import { KebabCase } from 'type-fest'; +import { BadRequestException } from '@nestjs/common'; +import { basename } from 'path'; +import { settings } from 'src/constants/settings'; +import { camelCase } from 'src/utils/camel-case'; + +type AllowedFolders = KebabCase; + +export function checkFilePath(filePath: string): string { + const allowedFolders = Object.values(FileFolder).map((value) => + kebabCase(value), + ); + + const sanitizedFilePath = filePath.replace(/\0/g, ''); + const [folder, size] = sanitizedFilePath.split('/'); + + if (!allowedFolders.includes(folder as AllowedFolders)) { + throw new BadRequestException(`Folder ${folder} is not allowed`); + } + + if ( + size && + !settings.storage.imageCropSizes[camelCase(folder)]?.includes(size) + ) { + throw new BadRequestException(`Size ${size} is not allowed`); + } + + return sanitizedFilePath; +} + +export function checkFilename(filename: string) { + const sanitizedFilename = basename(filename.replace(/\0/g, '')); + + if ( + !sanitizedFilename || + sanitizedFilename.includes('/') || + sanitizedFilename.includes('\\') || + !sanitizedFilename.includes('.') + ) { + throw new BadRequestException(`Filename is not allowed`); + } + + return basename(sanitizedFilename); +} diff --git a/server/src/core/file/interfaces/file-folder.interface.ts b/server/src/core/file/interfaces/file-folder.interface.ts new file mode 100644 index 000000000000..45c8a4d6d1e3 --- /dev/null +++ b/server/src/core/file/interfaces/file-folder.interface.ts @@ -0,0 +1,9 @@ +import { registerEnumType } from '@nestjs/graphql'; + +export enum FileFolder { + ProfilePicture = 'profilePicture', +} + +registerEnumType(FileFolder, { + name: 'FileFolder', +}); diff --git a/server/src/core/file/resolvers/file-upload.resolver.spec.ts b/server/src/core/file/resolvers/file-upload.resolver.spec.ts new file mode 100644 index 000000000000..ebe8dae332f3 --- /dev/null +++ b/server/src/core/file/resolvers/file-upload.resolver.spec.ts @@ -0,0 +1,25 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { FileUploadResolver } from './file-upload.resolver'; +import { FileUploadService } from '../services/file-upload.service'; + +describe('FileUploadResolver', () => { + let resolver: FileUploadResolver; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + FileUploadResolver, + { + provide: FileUploadService, + useValue: {}, + }, + ], + }).compile(); + + resolver = module.get(FileUploadResolver); + }); + + it('should be defined', () => { + expect(resolver).toBeDefined(); + }); +}); diff --git a/server/src/core/file/resolvers/file-upload.resolver.ts b/server/src/core/file/resolvers/file-upload.resolver.ts new file mode 100644 index 000000000000..20348e220654 --- /dev/null +++ b/server/src/core/file/resolvers/file-upload.resolver.ts @@ -0,0 +1,60 @@ +import { Args, Mutation, Resolver } from '@nestjs/graphql'; +import { GraphQLUpload, FileUpload } from 'graphql-upload'; +import { v4 as uuidV4 } from 'uuid'; +import { FileUploadService } from '../services/file-upload.service'; +import { UseGuards } from '@nestjs/common'; +import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; +import { streamToBuffer } from 'src/utils/stream-to-buffer'; +import { FileFolder } from '../interfaces/file-folder.interface'; + +@UseGuards(JwtAuthGuard) +@Resolver() +export class FileUploadResolver { + constructor(private readonly fileUploadService: FileUploadService) {} + + @Mutation(() => String) + async uploadFile( + @Args({ name: 'file', type: () => GraphQLUpload }) + { createReadStream, filename, mimetype }: FileUpload, + @Args('fileFolder', { type: () => FileFolder, nullable: true }) + fileFolder: FileFolder, + ): Promise { + const stream = createReadStream(); + const buffer = await streamToBuffer(stream); + const ext = filename.split('.')?.[1]; + const id = uuidV4(); + const name = `${id}${ext ? `.${ext}` : ''}`; + + const path = await this.fileUploadService.uploadFile({ + file: buffer, + name, + mimeType: mimetype, + fileFolder, + }); + + return path.name; + } + + @Mutation(() => String) + async uploadImage( + @Args({ name: 'file', type: () => GraphQLUpload }) + { createReadStream, filename, mimetype }: FileUpload, + @Args('fileFolder', { type: () => FileFolder, nullable: true }) + fileFolder: FileFolder, + ): Promise { + const stream = createReadStream(); + const buffer = await streamToBuffer(stream); + const ext = filename.split('.')?.[1]; + const id = uuidV4(); + const name = `${id}${ext ? `.${ext}` : ''}`; + + const path = await this.fileUploadService.uploadImage({ + file: buffer, + name, + mimeType: mimetype, + fileFolder, + }); + + return path.name; + } +} diff --git a/server/src/core/file/services/file-upload.service.spec.ts b/server/src/core/file/services/file-upload.service.spec.ts new file mode 100644 index 000000000000..ab092c1e8dac --- /dev/null +++ b/server/src/core/file/services/file-upload.service.spec.ts @@ -0,0 +1,35 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { FileUploadService } from './file-upload.service'; +import { S3StorageService } from 'src/integrations/s3-storage/s3-storage.service'; +import { LocalStorageService } from 'src/integrations/local-storage/local-storage.service'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; + +describe('FileUploadService', () => { + let service: FileUploadService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + FileUploadService, + { + provide: S3StorageService, + useValue: {}, + }, + { + provide: LocalStorageService, + useValue: {}, + }, + { + provide: EnvironmentService, + useValue: {}, + }, + ], + }).compile(); + + service = module.get(FileUploadService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/server/src/core/file/services/file-upload.service.ts b/server/src/core/file/services/file-upload.service.ts new file mode 100644 index 000000000000..779113d5eb0b --- /dev/null +++ b/server/src/core/file/services/file-upload.service.ts @@ -0,0 +1,135 @@ +import { Injectable } from '@nestjs/common'; +import sharp from 'sharp'; +import { S3StorageService } from 'src/integrations/s3-storage/s3-storage.service'; +import { kebabCase } from 'src/utils/kebab-case'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; +import { LocalStorageService } from 'src/integrations/local-storage/local-storage.service'; +import { getCropSize } from 'src/utils/image'; +import { settings } from 'src/constants/settings'; +import { FileFolder } from '../interfaces/file-folder.interface'; + +@Injectable() +export class FileUploadService { + constructor( + private readonly s3Storage: S3StorageService, + private readonly localStorage: LocalStorageService, + private readonly environmentService: EnvironmentService, + ) {} + + async uploadFile({ + file, + name, + mimeType, + fileFolder, + }: { + file: Buffer | Uint8Array | string; + name: string; + mimeType: string | undefined; + fileFolder: FileFolder; + }) { + const storageType = this.environmentService.getStorageType(); + + switch (storageType) { + case 's3': { + await this.uploadFileToS3(file, name, mimeType, fileFolder); + return { + name: `/${name}`, + }; + } + case 'local': + default: { + await this.uploadToLocal(file, name, fileFolder); + return { + name: `/${name}`, + }; + } + } + } + + async uploadImage({ + file, + name, + mimeType, + fileFolder, + }: { + file: Buffer | Uint8Array | string; + name: string; + mimeType: string | undefined; + fileFolder: FileFolder; + }) { + // Get all cropSizes for this fileFolder + const cropSizes = settings.storage.imageCropSizes[fileFolder]; + // Extract the values from ShortCropSize + const sizes = cropSizes.map((shortSize) => getCropSize(shortSize)); + // Crop images based on sizes + const images = await Promise.all( + sizes.map((size) => + sharp(file).resize({ + [size?.type || 'width']: size?.value ?? undefined, + }), + ), + ); + + // Upload all images to corresponding folders + await Promise.all( + images.map(async (image, index) => { + const buffer = await image.toBuffer(); + + return this.uploadFile({ + file: buffer, + name: `${cropSizes[index]}/${name}`, + mimeType, + fileFolder, + }); + }), + ); + + return { + name: `/${name}`, + }; + } + + private async uploadToLocal( + file: Buffer | Uint8Array | string, + name: string, + fileFolder: FileFolder, + ): Promise { + const folderName = kebabCase(fileFolder.toString()); + + try { + const result = await this.localStorage.uploadFile({ + file, + name, + folder: folderName, + }); + + return result; + } catch (err) { + console.log('uploadFile error: ', err); + throw err; + } + } + + private async uploadFileToS3( + file: Buffer | Uint8Array | string, + name: string, + mimeType: string | undefined, + fileFolder: FileFolder, + ) { + // Aws only accept bucket with kebab-case name + const bucketFolderName = kebabCase(fileFolder.toString()); + + try { + const result = await this.s3Storage.uploadFile({ + Key: `${bucketFolderName}/${name}`, + Body: file, + ContentType: mimeType, + }); + + return result; + } catch (err) { + console.log('uploadFile error: ', err); + throw err; + } + } +} diff --git a/server/src/core/file/services/file.service.spec.ts b/server/src/core/file/services/file.service.spec.ts new file mode 100644 index 000000000000..9f425584e25d --- /dev/null +++ b/server/src/core/file/services/file.service.spec.ts @@ -0,0 +1,30 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { FileService } from './file.service'; +import { S3StorageService } from 'src/integrations/s3-storage/s3-storage.service'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; + +describe('FileService', () => { + let service: FileService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + FileService, + { + provide: S3StorageService, + useValue: {}, + }, + { + provide: EnvironmentService, + useValue: {}, + }, + ], + }).compile(); + + service = module.get(FileService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/server/src/core/file/services/file.service.ts b/server/src/core/file/services/file.service.ts new file mode 100644 index 000000000000..4628b004c237 --- /dev/null +++ b/server/src/core/file/services/file.service.ts @@ -0,0 +1,55 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { S3StorageService } from 'src/integrations/s3-storage/s3-storage.service'; +import { EnvironmentService } from 'src/integrations/environment/environment.service'; +import { createReadStream } from 'fs'; +import { join } from 'path'; +import { Readable } from 'stream'; + +@Injectable() +export class FileService { + constructor( + private readonly s3Storage: S3StorageService, + private readonly environmentService: EnvironmentService, + ) {} + + async getFileStream(folderPath: string, filename: string) { + const storageType = this.environmentService.getStorageType(); + + switch (storageType) { + case 's3': + return this.getS3FileStream(folderPath, filename); + case 'local': + default: + return this.getLocalFileStream(folderPath, filename); + } + } + + private async getLocalFileStream(folderPath: string, filename: string) { + const storageLocation = this.environmentService.getStorageLocation(); + + const filePath = join( + process.cwd(), + `${storageLocation}/`, + folderPath, + filename, + ); + + return createReadStream(filePath); + } + + private async getS3FileStream(folderPath: string, filename: string) { + try { + const file = await this.s3Storage.getFile({ + Key: `${folderPath}/${filename}`, + }); + + if (!file || !file.Body || !(file.Body instanceof Readable)) { + throw new Error('Unable to get file stream'); + } + + return Readable.from(file.Body); + } catch (error) { + throw new NotFoundException('File not found'); + } + } +} diff --git a/server/src/integrations/environment/decorators/is-aws-region.decorator.ts b/server/src/integrations/environment/decorators/is-aws-region.decorator.ts new file mode 100644 index 000000000000..de1bf1c9da7a --- /dev/null +++ b/server/src/integrations/environment/decorators/is-aws-region.decorator.ts @@ -0,0 +1,26 @@ +import { + registerDecorator, + ValidationOptions, + ValidatorConstraint, + ValidatorConstraintInterface, +} from 'class-validator'; + +@ValidatorConstraint({ async: true }) +export class IsAWSRegionConstraint implements ValidatorConstraintInterface { + validate(region: string) { + const regex = /^[a-z]{2}-[a-z]+-\d{1}$/; + return regex.test(region); // Returns true if region matches regex + } +} + +export function IsAWSRegion(validationOptions?: ValidationOptions) { + return function (object: object, propertyName: string) { + registerDecorator({ + target: object.constructor, + propertyName: propertyName, + options: validationOptions, + constraints: [], + validator: IsAWSRegionConstraint, + }); + }; +} diff --git a/server/src/integrations/environment/decorators/is-duration.decorator.ts b/server/src/integrations/environment/decorators/is-duration.decorator.ts new file mode 100644 index 000000000000..138402005e5e --- /dev/null +++ b/server/src/integrations/environment/decorators/is-duration.decorator.ts @@ -0,0 +1,27 @@ +import { + registerDecorator, + ValidationOptions, + ValidatorConstraint, + ValidatorConstraintInterface, +} from 'class-validator'; + +@ValidatorConstraint({ async: true }) +export class IsDurationConstraint implements ValidatorConstraintInterface { + validate(duration: string) { + const regex = + /^-?[0-9]+(.[0-9]+)?(m(illiseconds?)?|s(econds?)?|h((ou)?rs?)?|d(ays?)?|w(eeks?)?|M(onths?)?|y(ears?)?)?$/; + return regex.test(duration); // Returns true if duration matches regex + } +} + +export function IsDuration(validationOptions?: ValidationOptions) { + return function (object: object, propertyName: string) { + registerDecorator({ + target: object.constructor, + propertyName: propertyName, + options: validationOptions, + constraints: [], + validator: IsDurationConstraint, + }); + }; +} diff --git a/server/src/integrations/environment/environment.module-definition.ts b/server/src/integrations/environment/environment.module-definition.ts new file mode 100644 index 000000000000..242e2ef3cddf --- /dev/null +++ b/server/src/integrations/environment/environment.module-definition.ts @@ -0,0 +1,8 @@ +import { ConfigurableModuleBuilder } from '@nestjs/common'; + +export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = + new ConfigurableModuleBuilder({ + moduleName: 'Environment', + }) + .setClassMethodName('forRoot') + .build(); diff --git a/server/src/integrations/environment/environment.module.ts b/server/src/integrations/environment/environment.module.ts new file mode 100644 index 000000000000..7d901ab1feb2 --- /dev/null +++ b/server/src/integrations/environment/environment.module.ts @@ -0,0 +1,19 @@ +import { Global, Module } from '@nestjs/common'; +import { EnvironmentService } from './environment.service'; +import { ConfigurableModuleClass } from './environment.module-definition'; +import { ConfigModule } from '@nestjs/config'; +import { validate } from './environment.validation'; + +@Global() +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + expandVariables: true, + validate, + }), + ], + providers: [EnvironmentService], + exports: [EnvironmentService], +}) +export class EnvironmentModule extends ConfigurableModuleClass {} diff --git a/server/src/integrations/environment/environment.service.spec.ts b/server/src/integrations/environment/environment.service.spec.ts new file mode 100644 index 000000000000..7184e5fa4aa0 --- /dev/null +++ b/server/src/integrations/environment/environment.service.spec.ts @@ -0,0 +1,25 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { EnvironmentService } from './environment.service'; +import { ConfigService } from '@nestjs/config'; + +describe('EnvironmentService', () => { + let service: EnvironmentService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + EnvironmentService, + { + provide: ConfigService, + useValue: {}, + }, + ], + }).compile(); + + service = module.get(EnvironmentService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/server/src/integrations/environment/environment.service.ts b/server/src/integrations/environment/environment.service.ts new file mode 100644 index 000000000000..acc04664391f --- /dev/null +++ b/server/src/integrations/environment/environment.service.ts @@ -0,0 +1,66 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { AwsRegion } from './interfaces/aws-region.interface'; +import { StorageType } from './interfaces/storage.interface'; + +@Injectable() +export class EnvironmentService { + constructor(private configService: ConfigService) {} + + getPGDatabaseUrl(): string { + return this.configService.get('PG_DATABASE_URL')!; + } + + getAccessTokenSecret(): string { + return this.configService.get('ACCESS_TOKEN_SECRET')!; + } + + getAccessTokenExpiresIn(): string { + return this.configService.get('ACCESS_TOKEN_EXPIRES_IN')!; + } + + getRefreshTokenSecret(): string { + return this.configService.get('REFRESH_TOKEN_SECRET')!; + } + + getRefreshTokenExpiresIn(): string { + return this.configService.get('REFRESH_TOKEN_EXPIRES_IN')!; + } + + getLoginTokenSecret(): string { + return this.configService.get('LOGIN_TOKEN_SECRET')!; + } + + getLoginTokenExpiresIn(): string { + return this.configService.get('LOGIN_TOKEN_EXPIRES_IN')!; + } + + getFrontAuthCallbackUrl(): string { + return this.configService.get('FRONT_AUTH_CALLBACK_URL')!; + } + + getAuthGoogleClientId(): string | undefined { + return this.configService.get('AUTH_GOOGLE_CLIENT_ID'); + } + + getAuthGoogleClientSecret(): string | undefined { + return this.configService.get('AUTH_GOOGLE_CLIENT_SECRET'); + } + + getAuthGoogleCallbackUrl(): string | undefined { + return this.configService.get('AUTH_GOOGLE_CALLBACK_URL'); + } + + getStorageType(): StorageType | undefined { + return this.configService.get('STORAGE_TYPE'); + } + + getStorageRegion(): AwsRegion | undefined { + return this.configService.get('STORAGE_REGION'); + } + + getStorageLocation(): string { + return this.configService.get('STORAGE_LOCATION')!; + } +} diff --git a/server/src/integrations/environment/environment.validation.ts b/server/src/integrations/environment/environment.validation.ts new file mode 100644 index 000000000000..fe4b8cba90b3 --- /dev/null +++ b/server/src/integrations/environment/environment.validation.ts @@ -0,0 +1,77 @@ +import { plainToClass } from 'class-transformer'; +import { + IsEnum, + IsOptional, + IsString, + IsUrl, + ValidateIf, + validateSync, +} from 'class-validator'; +import { assert } from 'src/utils/assert'; +import { IsDuration } from './decorators/is-duration.decorator'; +import { StorageType } from './interfaces/storage.interface'; +import { AwsRegion } from './interfaces/aws-region.interface'; +import { IsAWSRegion } from './decorators/is-aws-region.decorator'; + +export class EnvironmentVariables { + // Database + @IsUrl({ protocols: ['postgres'], require_tld: false }) + PG_DATABASE_URL: string; + + // Json Web Token + @IsString() + ACCESS_TOKEN_SECRET: string; + @IsDuration() + ACCESS_TOKEN_EXPIRES_IN: string; + + @IsString() + REFRESH_TOKEN_SECRET: string; + @IsDuration() + REFRESH_TOKEN_EXPIRES_IN: string; + + @IsString() + LOGIN_TOKEN_SECRET: string; + @IsDuration() + LOGIN_TOKEN_EXPIRES_IN: string; + + // Auth + @IsUrl({ require_tld: false }) + FRONT_AUTH_CALLBACK_URL: string; + + @IsString() + @IsOptional() + AUTH_GOOGLE_CLIENT_ID?: string; + + @IsString() + @IsOptional() + AUTH_GOOGLE_CLIENT_SECRET?: string; + + @IsUrl({ require_tld: false }) + @IsOptional() + AUTH_GOOGLE_CALLBACK_URL?: string; + + // Storage + @IsEnum(StorageType) + @IsOptional() + STORAGE_TYPE?: StorageType; + + @ValidateIf((_, value) => value === StorageType.S3) + @IsAWSRegion() + STORAGE_REGION?: AwsRegion; + + @IsString() + STORAGE_LOCATION: string; +} + +export function validate(config: Record) { + const validatedConfig = plainToClass(EnvironmentVariables, config, { + enableImplicitConversion: true, + }); + + const errors = validateSync(validatedConfig, { + skipMissingProperties: false, + }); + assert(!errors.length, errors.toString()); + + return validatedConfig; +} diff --git a/server/src/integrations/environment/interfaces/aws-region.interface.ts b/server/src/integrations/environment/interfaces/aws-region.interface.ts new file mode 100644 index 000000000000..4ed97bb6725f --- /dev/null +++ b/server/src/integrations/environment/interfaces/aws-region.interface.ts @@ -0,0 +1 @@ +export type AwsRegion = `${string}-${string}-${number}`; diff --git a/server/src/integrations/environment/interfaces/storage.interface.ts b/server/src/integrations/environment/interfaces/storage.interface.ts new file mode 100644 index 000000000000..78433a2d1115 --- /dev/null +++ b/server/src/integrations/environment/interfaces/storage.interface.ts @@ -0,0 +1,4 @@ +export enum StorageType { + S3 = 's3', + Local = 'local', +} diff --git a/server/src/integrations/integrations.module.ts b/server/src/integrations/integrations.module.ts new file mode 100644 index 000000000000..e388db98c506 --- /dev/null +++ b/server/src/integrations/integrations.module.ts @@ -0,0 +1,69 @@ +import { Module } from '@nestjs/common'; +import { fromNodeProviderChain } from '@aws-sdk/credential-providers'; +import { S3StorageModule } from './s3-storage/s3-storage.module'; +import { S3StorageModuleOptions } from './s3-storage/interfaces'; +import { LocalStorageModule } from './local-storage/local-storage.module'; +import { LocalStorageModuleOptions } from './local-storage/interfaces'; +import { EnvironmentModule } from './environment/environment.module'; +import { EnvironmentService } from './environment/environment.service'; +import { assert } from 'src/utils/assert'; + +/** + * S3 Storage Module factory + * @param config + * @returns S3ModuleOptions + */ +const S3StorageModuleFactory = async ( + environmentService: EnvironmentService, +): Promise => { + const fileSystem = environmentService.getStorageType(); + const bucketName = environmentService.getStorageLocation(); + const region = environmentService.getStorageRegion(); + + if (fileSystem === 'local') { + return { bucketName }; + } + + assert(region, 'S3 region is not defined'); + + return { + bucketName, + credentials: fromNodeProviderChain({ + clientConfig: { region }, + }), + forcePathStyle: true, + region, + }; +}; + +/** + * LocalStorage Module factory + * @param environment + * @returns LocalStorageModuleOptions + */ +const localStorageModuleFactory = async ( + environmentService: EnvironmentService, +): Promise => { + const folderName = environmentService.getStorageLocation(); + + return { + storagePath: process.cwd() + '/' + folderName, + }; +}; + +@Module({ + imports: [ + S3StorageModule.forRootAsync({ + useFactory: S3StorageModuleFactory, + inject: [EnvironmentService], + }), + LocalStorageModule.forRootAsync({ + useFactory: localStorageModuleFactory, + inject: [EnvironmentService], + }), + EnvironmentModule.forRoot({}), + ], + exports: [], + providers: [], +}) +export class IntegrationsModule {} diff --git a/server/src/integrations/local-storage/interfaces/index.ts b/server/src/integrations/local-storage/interfaces/index.ts new file mode 100644 index 000000000000..eeafd32c310d --- /dev/null +++ b/server/src/integrations/local-storage/interfaces/index.ts @@ -0,0 +1 @@ +export * from './local-storage.interface'; diff --git a/server/src/integrations/local-storage/interfaces/local-storage.interface.ts b/server/src/integrations/local-storage/interfaces/local-storage.interface.ts new file mode 100644 index 000000000000..b5ac7f6bd0ac --- /dev/null +++ b/server/src/integrations/local-storage/interfaces/local-storage.interface.ts @@ -0,0 +1,3 @@ +export interface LocalStorageModuleOptions { + storagePath: string; +} diff --git a/server/src/integrations/local-storage/local-storage.module-definition.ts b/server/src/integrations/local-storage/local-storage.module-definition.ts new file mode 100644 index 000000000000..9fe25f7eeef4 --- /dev/null +++ b/server/src/integrations/local-storage/local-storage.module-definition.ts @@ -0,0 +1,9 @@ +import { ConfigurableModuleBuilder } from '@nestjs/common'; +import { LocalStorageModuleOptions } from './interfaces'; + +export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = + new ConfigurableModuleBuilder({ + moduleName: 'LocalStorage', + }) + .setClassMethodName('forRoot') + .build(); diff --git a/server/src/integrations/local-storage/local-storage.module.ts b/server/src/integrations/local-storage/local-storage.module.ts new file mode 100644 index 000000000000..bb4f0d4308c4 --- /dev/null +++ b/server/src/integrations/local-storage/local-storage.module.ts @@ -0,0 +1,10 @@ +import { Global, Module } from '@nestjs/common'; +import { LocalStorageService } from './local-storage.service'; +import { ConfigurableModuleClass } from './local-storage.module-definition'; + +@Global() +@Module({ + providers: [LocalStorageService], + exports: [LocalStorageService], +}) +export class LocalStorageModule extends ConfigurableModuleClass {} diff --git a/server/src/integrations/local-storage/local-storage.service.spec.ts b/server/src/integrations/local-storage/local-storage.service.spec.ts new file mode 100644 index 000000000000..754462a63414 --- /dev/null +++ b/server/src/integrations/local-storage/local-storage.service.spec.ts @@ -0,0 +1,25 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { LocalStorageService } from './local-storage.service'; +import { MODULE_OPTIONS_TOKEN } from './local-storage.module-definition'; + +describe('LocalStorageService', () => { + let service: LocalStorageService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + LocalStorageService, + { + provide: MODULE_OPTIONS_TOKEN, + useValue: {}, + }, + ], + }).compile(); + + service = module.get(LocalStorageService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/server/src/integrations/local-storage/local-storage.service.ts b/server/src/integrations/local-storage/local-storage.service.ts new file mode 100644 index 000000000000..bb8dcffeab2f --- /dev/null +++ b/server/src/integrations/local-storage/local-storage.service.ts @@ -0,0 +1,35 @@ +import { Injectable, Inject } from '@nestjs/common'; +import * as fs from 'fs/promises'; +import { existsSync } from 'fs'; +import * as path from 'path'; +import { MODULE_OPTIONS_TOKEN } from './local-storage.module-definition'; +import { LocalStorageModuleOptions } from './interfaces'; + +@Injectable() +export class LocalStorageService { + constructor( + @Inject(MODULE_OPTIONS_TOKEN) + private readonly options: LocalStorageModuleOptions, + ) {} + + async createFolder(path: string) { + if (existsSync(path)) { + return; + } + + return fs.mkdir(path, { recursive: true }); + } + + async uploadFile(params: { + file: Buffer | Uint8Array | string; + name: string; + folder: string; + }) { + const filePath = `${this.options.storagePath}/${params.folder}/${params.name}`; + const folderPath = path.dirname(filePath); + + await this.createFolder(folderPath); + + return fs.writeFile(filePath, params.file); + } +} diff --git a/server/src/integrations/s3-storage/interfaces/index.ts b/server/src/integrations/s3-storage/interfaces/index.ts new file mode 100644 index 000000000000..52408298f33a --- /dev/null +++ b/server/src/integrations/s3-storage/interfaces/index.ts @@ -0,0 +1 @@ +export * from './s3-storage-module.interface'; diff --git a/server/src/integrations/s3-storage/interfaces/s3-storage-module.interface.ts b/server/src/integrations/s3-storage/interfaces/s3-storage-module.interface.ts new file mode 100644 index 000000000000..2951d1553513 --- /dev/null +++ b/server/src/integrations/s3-storage/interfaces/s3-storage-module.interface.ts @@ -0,0 +1,5 @@ +import { S3ClientConfig } from '@aws-sdk/client-s3'; + +export interface S3StorageModuleOptions extends S3ClientConfig { + bucketName: string; +} diff --git a/server/src/integrations/s3-storage/s3-storage.module-definition.ts b/server/src/integrations/s3-storage/s3-storage.module-definition.ts new file mode 100644 index 000000000000..ccb3fef88cab --- /dev/null +++ b/server/src/integrations/s3-storage/s3-storage.module-definition.ts @@ -0,0 +1,9 @@ +import { ConfigurableModuleBuilder } from '@nestjs/common'; +import { S3StorageModuleOptions } from './interfaces'; + +export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = + new ConfigurableModuleBuilder({ + moduleName: 'S3Storage', + }) + .setClassMethodName('forRoot') + .build(); diff --git a/server/src/integrations/s3-storage/s3-storage.module.ts b/server/src/integrations/s3-storage/s3-storage.module.ts new file mode 100644 index 000000000000..e17d27f1c68f --- /dev/null +++ b/server/src/integrations/s3-storage/s3-storage.module.ts @@ -0,0 +1,10 @@ +import { Global, Module } from '@nestjs/common'; +import { S3StorageService } from './s3-storage.service'; +import { ConfigurableModuleClass } from './s3-storage.module-definition'; + +@Global() +@Module({ + providers: [S3StorageService], + exports: [S3StorageService], +}) +export class S3StorageModule extends ConfigurableModuleClass {} diff --git a/server/src/integrations/s3-storage/s3-storage.service.spec.ts b/server/src/integrations/s3-storage/s3-storage.service.spec.ts new file mode 100644 index 000000000000..231dbb659919 --- /dev/null +++ b/server/src/integrations/s3-storage/s3-storage.service.spec.ts @@ -0,0 +1,25 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { S3StorageService } from './s3-storage.service'; +import { MODULE_OPTIONS_TOKEN } from './s3-storage.module-definition'; + +describe('S3StorageService', () => { + let service: S3StorageService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + S3StorageService, + { + provide: MODULE_OPTIONS_TOKEN, + useValue: {}, + }, + ], + }).compile(); + + service = module.get(S3StorageService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/server/src/integrations/s3-storage/s3-storage.service.ts b/server/src/integrations/s3-storage/s3-storage.service.ts new file mode 100644 index 000000000000..f02f1d732bde --- /dev/null +++ b/server/src/integrations/s3-storage/s3-storage.service.ts @@ -0,0 +1,86 @@ +import { Injectable, Inject } from '@nestjs/common'; +import { MODULE_OPTIONS_TOKEN } from './s3-storage.module-definition'; +import { S3StorageModuleOptions } from './interfaces'; +import { + CreateBucketCommandInput, + GetObjectCommand, + GetObjectCommandInput, + GetObjectCommandOutput, + HeadBucketCommandInput, + NotFound, + PutObjectCommand, + PutObjectCommandInput, + PutObjectCommandOutput, + S3, +} from '@aws-sdk/client-s3'; + +@Injectable() +export class S3StorageService { + private s3Client: S3; + private bucketName: string; + + constructor( + @Inject(MODULE_OPTIONS_TOKEN) + private readonly options: S3StorageModuleOptions, + ) { + const { bucketName, ...s3Options } = options; + + this.s3Client = new S3(s3Options); + this.bucketName = bucketName; + } + + public get client(): S3 { + return this.s3Client; + } + + async uploadFile( + params: Omit, + ): Promise { + const command = new PutObjectCommand({ + ...params, + Bucket: this.bucketName, + }); + + await this.createBucket({ Bucket: this.bucketName }); + + return this.s3Client.send(command); + } + + async getFile( + params: Omit, + ): Promise { + const command = new GetObjectCommand({ + ...params, + Bucket: this.bucketName, + }); + + return this.s3Client.send(command); + } + + async checkBucketExists(args: HeadBucketCommandInput) { + try { + await this.s3Client.headBucket(args); + + return true; + } catch (error) { + console.log(error); + if (error instanceof NotFound) { + return false; + } + + throw error; + } + } + + async createBucket(args: CreateBucketCommandInput) { + const exist = await this.checkBucketExists({ + Bucket: args.Bucket, + }); + + if (exist) { + return; + } + + return this.s3Client.createBucket(args); + } +} diff --git a/server/src/main.ts b/server/src/main.ts index 52ac9033ef61..0b0146d5033c 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -1,6 +1,7 @@ import { NestFactory } from '@nestjs/core'; import { ValidationPipe } from '@nestjs/common'; import { AppModule } from './app.module'; +import { graphqlUploadExpress } from 'graphql-upload'; async function bootstrap() { const app = await NestFactory.create(AppModule, { cors: true }); @@ -8,6 +9,9 @@ async function bootstrap() { // Apply validation pipes globally app.useGlobalPipes(new ValidationPipe()); + // Graphql file upload + app.use(graphqlUploadExpress()); + await app.listen(3000); } diff --git a/server/src/utils/camel-case.ts b/server/src/utils/camel-case.ts new file mode 100644 index 000000000000..c5eaafed94d7 --- /dev/null +++ b/server/src/utils/camel-case.ts @@ -0,0 +1,26 @@ +import isObject from 'lodash.isobject'; +import lodashCamelCase from 'lodash.camelcase'; +import { CamelCase, CamelCasedPropertiesDeep } from 'type-fest'; + +export const camelCase = (text: T) => + lodashCamelCase(text as unknown as string) as CamelCase; + +export const camelCaseDeep = (value: T): CamelCasedPropertiesDeep => { + // Check if it's an array + if (Array.isArray(value)) { + return value.map(camelCaseDeep) as CamelCasedPropertiesDeep; + } + + // Check if it's an object + if (isObject(value)) { + const result: Record = {}; + + for (const key in value) { + result[camelCase(key)] = camelCaseDeep(value[key]); + } + + return result as CamelCasedPropertiesDeep; + } + + return value as CamelCasedPropertiesDeep; +}; diff --git a/server/src/utils/image.ts b/server/src/utils/image.ts new file mode 100644 index 000000000000..e659cfb216ea --- /dev/null +++ b/server/src/utils/image.ts @@ -0,0 +1,21 @@ +const cropRegex = /([w|h])([0-9]+)/; + +export type ShortCropSize = `${'w' | 'h'}${number}` | 'original'; + +export interface CropSize { + type: 'width' | 'height'; + value: number; +} + +export const getCropSize = (value: ShortCropSize): CropSize | null => { + const match = value.match(cropRegex); + + if (value === 'original' || match === null) { + return null; + } + + return { + type: match[1] === 'w' ? 'width' : 'height', + value: +match[2], + }; +}; diff --git a/server/src/utils/kebab-case.ts b/server/src/utils/kebab-case.ts new file mode 100644 index 000000000000..62cf52412af5 --- /dev/null +++ b/server/src/utils/kebab-case.ts @@ -0,0 +1,26 @@ +import isObject from 'lodash.isobject'; +import lodashKebabCase from 'lodash.kebabcase'; +import { KebabCase, KebabCasedPropertiesDeep } from 'type-fest'; + +export const kebabCase = (text: T) => + lodashKebabCase(text as unknown as string) as KebabCase; + +export const kebabCaseDeep = (value: T): KebabCasedPropertiesDeep => { + // Check if it's an array + if (Array.isArray(value)) { + return value.map(kebabCaseDeep) as KebabCasedPropertiesDeep; + } + + // Check if it's an object + if (isObject(value)) { + const result: Record = {}; + + for (const key in value) { + result[kebabCase(key)] = kebabCaseDeep(value[key]); + } + + return result as KebabCasedPropertiesDeep; + } + + return value as KebabCasedPropertiesDeep; +}; diff --git a/server/src/utils/stream-to-buffer.ts b/server/src/utils/stream-to-buffer.ts new file mode 100644 index 000000000000..80608a91783a --- /dev/null +++ b/server/src/utils/stream-to-buffer.ts @@ -0,0 +1,11 @@ +import { Readable } from 'stream'; + +export async function streamToBuffer(stream: Readable): Promise { + const chunks: any[] = []; + + for await (const chunk of stream) { + chunks.push(chunk); + } + + return Buffer.concat(chunks); +} diff --git a/server/yarn.lock b/server/yarn.lock index 1df8e9c5e460..a96ebbebfff5 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -286,6 +286,686 @@ dependencies: xss "^1.0.8" +"@aws-crypto/crc32@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-3.0.0.tgz#07300eca214409c33e3ff769cd5697b57fdd38fa" + integrity sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA== + dependencies: + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + tslib "^1.11.1" + +"@aws-crypto/crc32c@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz#016c92da559ef638a84a245eecb75c3e97cb664f" + integrity sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w== + dependencies: + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + tslib "^1.11.1" + +"@aws-crypto/ie11-detection@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz#640ae66b4ec3395cee6a8e94ebcd9f80c24cd688" + integrity sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q== + dependencies: + tslib "^1.11.1" + +"@aws-crypto/sha1-browser@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz#f9083c00782b24714f528b1a1fef2174002266a3" + integrity sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw== + dependencies: + "@aws-crypto/ie11-detection" "^3.0.0" + "@aws-crypto/supports-web-crypto" "^3.0.0" + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-crypto/sha256-browser@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz#05f160138ab893f1c6ba5be57cfd108f05827766" + integrity sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ== + dependencies: + "@aws-crypto/ie11-detection" "^3.0.0" + "@aws-crypto/sha256-js" "^3.0.0" + "@aws-crypto/supports-web-crypto" "^3.0.0" + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-crypto/sha256-js@3.0.0", "@aws-crypto/sha256-js@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz#f06b84d550d25521e60d2a0e2a90139341e007c2" + integrity sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ== + dependencies: + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + tslib "^1.11.1" + +"@aws-crypto/supports-web-crypto@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz#5d1bf825afa8072af2717c3e455f35cda0103ec2" + integrity sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg== + dependencies: + tslib "^1.11.1" + +"@aws-crypto/util@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-3.0.0.tgz#1c7ca90c29293f0883468ad48117937f0fe5bfb0" + integrity sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w== + dependencies: + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-sdk/chunked-blob-reader@3.310.0": + version "3.310.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/chunked-blob-reader/-/chunked-blob-reader-3.310.0.tgz#2ada1b024a2745c2fe7e869606fab781325f981e" + integrity sha512-CrJS3exo4mWaLnWxfCH+w88Ou0IcAZSIkk4QbmxiHl/5Dq705OLoxf4385MVyExpqpeVJYOYQ2WaD8i/pQZ2fg== + dependencies: + tslib "^2.5.0" + +"@aws-sdk/client-cognito-identity@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.363.0.tgz#75c94c3ea4dd1ef3bd5fefab3bde69dd19dbbb38" + integrity sha512-tsJzgBSCpna85IVsuS7FBIK9wkSl7fs8TJ/QzapIgu8rKss0ySHVO6TeMVAdw2BvaQl7CxU9c3PosjhLWHu6KQ== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/client-sts" "3.363.0" + "@aws-sdk/credential-provider-node" "3.363.0" + "@aws-sdk/middleware-host-header" "3.363.0" + "@aws-sdk/middleware-logger" "3.363.0" + "@aws-sdk/middleware-recursion-detection" "3.363.0" + "@aws-sdk/middleware-signing" "3.363.0" + "@aws-sdk/middleware-user-agent" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-endpoints" "3.357.0" + "@aws-sdk/util-user-agent-browser" "3.363.0" + "@aws-sdk/util-user-agent-node" "3.363.0" + "@smithy/config-resolver" "^1.0.1" + "@smithy/fetch-http-handler" "^1.0.1" + "@smithy/hash-node" "^1.0.1" + "@smithy/invalid-dependency" "^1.0.1" + "@smithy/middleware-content-length" "^1.0.1" + "@smithy/middleware-endpoint" "^1.0.1" + "@smithy/middleware-retry" "^1.0.2" + "@smithy/middleware-serde" "^1.0.1" + "@smithy/middleware-stack" "^1.0.1" + "@smithy/node-config-provider" "^1.0.1" + "@smithy/node-http-handler" "^1.0.2" + "@smithy/protocol-http" "^1.0.1" + "@smithy/smithy-client" "^1.0.3" + "@smithy/types" "^1.0.0" + "@smithy/url-parser" "^1.0.1" + "@smithy/util-base64" "^1.0.1" + "@smithy/util-body-length-browser" "^1.0.1" + "@smithy/util-body-length-node" "^1.0.1" + "@smithy/util-defaults-mode-browser" "^1.0.1" + "@smithy/util-defaults-mode-node" "^1.0.1" + "@smithy/util-retry" "^1.0.2" + "@smithy/util-utf8" "^1.0.1" + tslib "^2.5.0" + +"@aws-sdk/client-s3@^3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.363.0.tgz#757384d92c32a407ab0aaecf6f54d47cd9053514" + integrity sha512-LNnfg/t8wG5Fqj6l+PSV/t+IXDq9r3Kj9jEHn84513+p7bewXYSSreSpmLjG8OcKuMfHc9EJGNQ3DkMyFaLoWg== + dependencies: + "@aws-crypto/sha1-browser" "3.0.0" + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/client-sts" "3.363.0" + "@aws-sdk/credential-provider-node" "3.363.0" + "@aws-sdk/hash-blob-browser" "3.357.0" + "@aws-sdk/hash-stream-node" "3.357.0" + "@aws-sdk/md5-js" "3.357.0" + "@aws-sdk/middleware-bucket-endpoint" "3.363.0" + "@aws-sdk/middleware-expect-continue" "3.363.0" + "@aws-sdk/middleware-flexible-checksums" "3.363.0" + "@aws-sdk/middleware-host-header" "3.363.0" + "@aws-sdk/middleware-location-constraint" "3.363.0" + "@aws-sdk/middleware-logger" "3.363.0" + "@aws-sdk/middleware-recursion-detection" "3.363.0" + "@aws-sdk/middleware-sdk-s3" "3.363.0" + "@aws-sdk/middleware-signing" "3.363.0" + "@aws-sdk/middleware-ssec" "3.363.0" + "@aws-sdk/middleware-user-agent" "3.363.0" + "@aws-sdk/signature-v4-multi-region" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-endpoints" "3.357.0" + "@aws-sdk/util-user-agent-browser" "3.363.0" + "@aws-sdk/util-user-agent-node" "3.363.0" + "@aws-sdk/xml-builder" "3.310.0" + "@smithy/config-resolver" "^1.0.1" + "@smithy/eventstream-serde-browser" "^1.0.1" + "@smithy/eventstream-serde-config-resolver" "^1.0.1" + "@smithy/eventstream-serde-node" "^1.0.1" + "@smithy/fetch-http-handler" "^1.0.1" + "@smithy/hash-node" "^1.0.1" + "@smithy/invalid-dependency" "^1.0.1" + "@smithy/middleware-content-length" "^1.0.1" + "@smithy/middleware-endpoint" "^1.0.1" + "@smithy/middleware-retry" "^1.0.2" + "@smithy/middleware-serde" "^1.0.1" + "@smithy/middleware-stack" "^1.0.1" + "@smithy/node-config-provider" "^1.0.1" + "@smithy/node-http-handler" "^1.0.2" + "@smithy/protocol-http" "^1.0.1" + "@smithy/smithy-client" "^1.0.3" + "@smithy/types" "^1.0.0" + "@smithy/url-parser" "^1.0.1" + "@smithy/util-base64" "^1.0.1" + "@smithy/util-body-length-browser" "^1.0.1" + "@smithy/util-body-length-node" "^1.0.1" + "@smithy/util-defaults-mode-browser" "^1.0.1" + "@smithy/util-defaults-mode-node" "^1.0.1" + "@smithy/util-retry" "^1.0.2" + "@smithy/util-stream" "^1.0.1" + "@smithy/util-utf8" "^1.0.1" + "@smithy/util-waiter" "^1.0.1" + fast-xml-parser "4.2.5" + tslib "^2.5.0" + +"@aws-sdk/client-sso-oidc@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.363.0.tgz#71240d729a0847fd5a7aaac09ed5a3a07c3666cf" + integrity sha512-V3Ebiq/zNtDS/O92HUWGBa7MY59RYSsqWd+E0XrXv6VYTA00RlMTbNcseivNgp2UghOgB9a20Nkz6EqAeIN+RQ== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/middleware-host-header" "3.363.0" + "@aws-sdk/middleware-logger" "3.363.0" + "@aws-sdk/middleware-recursion-detection" "3.363.0" + "@aws-sdk/middleware-user-agent" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-endpoints" "3.357.0" + "@aws-sdk/util-user-agent-browser" "3.363.0" + "@aws-sdk/util-user-agent-node" "3.363.0" + "@smithy/config-resolver" "^1.0.1" + "@smithy/fetch-http-handler" "^1.0.1" + "@smithy/hash-node" "^1.0.1" + "@smithy/invalid-dependency" "^1.0.1" + "@smithy/middleware-content-length" "^1.0.1" + "@smithy/middleware-endpoint" "^1.0.1" + "@smithy/middleware-retry" "^1.0.2" + "@smithy/middleware-serde" "^1.0.1" + "@smithy/middleware-stack" "^1.0.1" + "@smithy/node-config-provider" "^1.0.1" + "@smithy/node-http-handler" "^1.0.2" + "@smithy/protocol-http" "^1.0.1" + "@smithy/smithy-client" "^1.0.3" + "@smithy/types" "^1.0.0" + "@smithy/url-parser" "^1.0.1" + "@smithy/util-base64" "^1.0.1" + "@smithy/util-body-length-browser" "^1.0.1" + "@smithy/util-body-length-node" "^1.0.1" + "@smithy/util-defaults-mode-browser" "^1.0.1" + "@smithy/util-defaults-mode-node" "^1.0.1" + "@smithy/util-retry" "^1.0.2" + "@smithy/util-utf8" "^1.0.1" + tslib "^2.5.0" + +"@aws-sdk/client-sso@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.363.0.tgz#b1939ee6769cf208f1dd4fbfa924c223da9d60ec" + integrity sha512-PZ+HfKSgS4hlMnJzG+Ev8/mgHd/b/ETlJWPSWjC/f2NwVoBQkBnqHjdyEx7QjF6nksJozcVh5Q+kkYLKc/QwBQ== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/middleware-host-header" "3.363.0" + "@aws-sdk/middleware-logger" "3.363.0" + "@aws-sdk/middleware-recursion-detection" "3.363.0" + "@aws-sdk/middleware-user-agent" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-endpoints" "3.357.0" + "@aws-sdk/util-user-agent-browser" "3.363.0" + "@aws-sdk/util-user-agent-node" "3.363.0" + "@smithy/config-resolver" "^1.0.1" + "@smithy/fetch-http-handler" "^1.0.1" + "@smithy/hash-node" "^1.0.1" + "@smithy/invalid-dependency" "^1.0.1" + "@smithy/middleware-content-length" "^1.0.1" + "@smithy/middleware-endpoint" "^1.0.1" + "@smithy/middleware-retry" "^1.0.2" + "@smithy/middleware-serde" "^1.0.1" + "@smithy/middleware-stack" "^1.0.1" + "@smithy/node-config-provider" "^1.0.1" + "@smithy/node-http-handler" "^1.0.2" + "@smithy/protocol-http" "^1.0.1" + "@smithy/smithy-client" "^1.0.3" + "@smithy/types" "^1.0.0" + "@smithy/url-parser" "^1.0.1" + "@smithy/util-base64" "^1.0.1" + "@smithy/util-body-length-browser" "^1.0.1" + "@smithy/util-body-length-node" "^1.0.1" + "@smithy/util-defaults-mode-browser" "^1.0.1" + "@smithy/util-defaults-mode-node" "^1.0.1" + "@smithy/util-retry" "^1.0.2" + "@smithy/util-utf8" "^1.0.1" + tslib "^2.5.0" + +"@aws-sdk/client-sts@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.363.0.tgz#c02b3cf3bd2ef9d54195323370db964cd1df4711" + integrity sha512-0jj14WvBPJQ8xr72cL0mhlmQ90tF0O0wqXwSbtog6PsC8+KDE6Yf+WsxsumyI8E5O8u3eYijBL+KdqG07F/y/w== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/credential-provider-node" "3.363.0" + "@aws-sdk/middleware-host-header" "3.363.0" + "@aws-sdk/middleware-logger" "3.363.0" + "@aws-sdk/middleware-recursion-detection" "3.363.0" + "@aws-sdk/middleware-sdk-sts" "3.363.0" + "@aws-sdk/middleware-signing" "3.363.0" + "@aws-sdk/middleware-user-agent" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-endpoints" "3.357.0" + "@aws-sdk/util-user-agent-browser" "3.363.0" + "@aws-sdk/util-user-agent-node" "3.363.0" + "@smithy/config-resolver" "^1.0.1" + "@smithy/fetch-http-handler" "^1.0.1" + "@smithy/hash-node" "^1.0.1" + "@smithy/invalid-dependency" "^1.0.1" + "@smithy/middleware-content-length" "^1.0.1" + "@smithy/middleware-endpoint" "^1.0.1" + "@smithy/middleware-retry" "^1.0.1" + "@smithy/middleware-serde" "^1.0.1" + "@smithy/middleware-stack" "^1.0.1" + "@smithy/node-config-provider" "^1.0.1" + "@smithy/node-http-handler" "^1.0.1" + "@smithy/protocol-http" "^1.1.0" + "@smithy/smithy-client" "^1.0.2" + "@smithy/types" "^1.1.0" + "@smithy/url-parser" "^1.0.1" + "@smithy/util-base64" "^1.0.1" + "@smithy/util-body-length-browser" "^1.0.1" + "@smithy/util-body-length-node" "^1.0.1" + "@smithy/util-defaults-mode-browser" "^1.0.1" + "@smithy/util-defaults-mode-node" "^1.0.1" + "@smithy/util-retry" "^1.0.1" + "@smithy/util-utf8" "^1.0.1" + fast-xml-parser "4.2.5" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-cognito-identity@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.363.0.tgz#0f4ae7cd282b61a5dfdd7d38a02495411c926dc9" + integrity sha512-5x42JvqEsBUrm6/qdf0WWe4mlmJjPItxamQhRjuOzeQD/BxsA2W5VS/7n0Ws0e27DNhlnUErcIJd+bBy6j1fqA== + dependencies: + "@aws-sdk/client-cognito-identity" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@smithy/property-provider" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-env@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.363.0.tgz#5b8471a243cdb54696ecae99ad4cc1c48d687657" + integrity sha512-VAQ3zITT2Q0acht0HezouYnMFKZ2vIOa20X4zQA3WI0HfaP4D6ga6KaenbDcb/4VFiqfqiRHfdyXHP0ThcDRMA== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/property-provider" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-ini@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.363.0.tgz#e77e65e1ffc7c736aa724ebdf038e99dca57a87b" + integrity sha512-ZYN+INoqyX5FVC3rqUxB6O8nOWkr0gHRRBm1suoOlmuFJ/WSlW/uUGthRBY5x1AQQnBF8cpdlxZzGHd41lFVNw== + dependencies: + "@aws-sdk/credential-provider-env" "3.363.0" + "@aws-sdk/credential-provider-process" "3.363.0" + "@aws-sdk/credential-provider-sso" "3.363.0" + "@aws-sdk/credential-provider-web-identity" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@smithy/credential-provider-imds" "^1.0.1" + "@smithy/property-provider" "^1.0.1" + "@smithy/shared-ini-file-loader" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-node@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.363.0.tgz#70815b3c8bc98d9afd148b851c8fdae9ce11fcd6" + integrity sha512-C1qXFIN2yMxD6pGgug0vR1UhScOki6VqdzuBHzXZAGu7MOjvgHNdscEcb3CpWnITHaPL2ztkiw75T1sZ7oIgQg== + dependencies: + "@aws-sdk/credential-provider-env" "3.363.0" + "@aws-sdk/credential-provider-ini" "3.363.0" + "@aws-sdk/credential-provider-process" "3.363.0" + "@aws-sdk/credential-provider-sso" "3.363.0" + "@aws-sdk/credential-provider-web-identity" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@smithy/credential-provider-imds" "^1.0.1" + "@smithy/property-provider" "^1.0.1" + "@smithy/shared-ini-file-loader" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-process@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.363.0.tgz#08608f6da246084f9b20481ac0de17f04ae54b4d" + integrity sha512-fOKAINU7Rtj2T8pP13GdCt+u0Ml3gYynp8ki+1jMZIQ+Ju/MdDOqZpKMFKicMn3Z1ttUOgqr+grUdus6z8ceBQ== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/property-provider" "^1.0.1" + "@smithy/shared-ini-file-loader" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-sso@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.363.0.tgz#949190c9ea510d9772aef9c61345575f4b40b44d" + integrity sha512-5RUZ5oM0lwZSo3EehT0dXggOjgtxFogpT3cZvoLGtIwrPBvm8jOQPXQUlaqCj10ThF1sYltEyukz/ovtDwYGew== + dependencies: + "@aws-sdk/client-sso" "3.363.0" + "@aws-sdk/token-providers" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@smithy/property-provider" "^1.0.1" + "@smithy/shared-ini-file-loader" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-web-identity@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.363.0.tgz#a5312519126ff7c3fea56ffefa0e51ef9383663c" + integrity sha512-Z6w7fjgy79pAax580wdixbStQw10xfyZ+hOYLcPudoYFKjoNx0NQBejg5SwBzCF/HQL23Ksm9kDfbXDX9fkPhA== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/property-provider" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/credential-providers@^3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-providers/-/credential-providers-3.363.0.tgz#592700058349ca6fcc3f23dfcec14c9d6c0c929a" + integrity sha512-hVa1DdYasnLud2EKjDAlDHiV/+H/Zq52chHU00c/R8XwPu1s0kZX3NMmlt0D2HhYqC1mUwtdmE58Jra2POviQQ== + dependencies: + "@aws-sdk/client-cognito-identity" "3.363.0" + "@aws-sdk/client-sso" "3.363.0" + "@aws-sdk/client-sts" "3.363.0" + "@aws-sdk/credential-provider-cognito-identity" "3.363.0" + "@aws-sdk/credential-provider-env" "3.363.0" + "@aws-sdk/credential-provider-ini" "3.363.0" + "@aws-sdk/credential-provider-node" "3.363.0" + "@aws-sdk/credential-provider-process" "3.363.0" + "@aws-sdk/credential-provider-sso" "3.363.0" + "@aws-sdk/credential-provider-web-identity" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@smithy/credential-provider-imds" "^1.0.1" + "@smithy/property-provider" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/hash-blob-browser@3.357.0": + version "3.357.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/hash-blob-browser/-/hash-blob-browser-3.357.0.tgz#e507929499fe0fe128664b67cd26f63f16ed4d25" + integrity sha512-RDd6UgrGHDmleTnXM9LRSSVa69euSAG2mlNhZMEDWk3OFseXVYqBDaqroVbQ01rM2UAe8MeBFchlV9OmxuVgvw== + dependencies: + "@aws-sdk/chunked-blob-reader" "3.310.0" + "@aws-sdk/types" "3.357.0" + tslib "^2.5.0" + +"@aws-sdk/hash-stream-node@3.357.0": + version "3.357.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/hash-stream-node/-/hash-stream-node-3.357.0.tgz#a78c6d1ae1c78cb52854311bad50988e8fc12142" + integrity sha512-KZjN1VAw1KHNp+xKVOWBGS+MpaYQTjZFD5f+7QQqW4TfbAkFFwIAEYIHq5Q8Gw+jVh0h61OrV/LyW3J2PVzc+w== + dependencies: + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-utf8" "3.310.0" + tslib "^2.5.0" + +"@aws-sdk/is-array-buffer@3.310.0": + version "3.310.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/is-array-buffer/-/is-array-buffer-3.310.0.tgz#f87a79f1b858c88744f07e8d8d0a791df204017e" + integrity sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ== + dependencies: + tslib "^2.5.0" + +"@aws-sdk/md5-js@3.357.0": + version "3.357.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/md5-js/-/md5-js-3.357.0.tgz#61853f562e71af0ec58aeede7883de122177ed55" + integrity sha512-to42sFAL7KgV/X9X40LLfEaNMHMGQL6/7mPMVCL/W2BZf3zw5OTl3lAaNyjXA+gO5Uo4lFEiQKAQVKNbr8b8Nw== + dependencies: + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-utf8" "3.310.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-bucket-endpoint@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.363.0.tgz#6c9b2dda20eaaf9171b7f2c4faff3b34b4331522" + integrity sha512-kR8+0X50zslpzRW29q4JbpPMadE1z39ZfGwPaBLKpoWvSGt4x+75FaoK71TH7urPPoFyD2Y+XKGA6YRYTUNHSQ== + dependencies: + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-arn-parser" "3.310.0" + "@smithy/protocol-http" "^1.1.0" + "@smithy/types" "^1.1.0" + "@smithy/util-config-provider" "^1.0.1" + tslib "^2.5.0" + +"@aws-sdk/middleware-expect-continue@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.363.0.tgz#125356f3685e14eaa8816383bbf5f3de05dd856e" + integrity sha512-I88xneZp6jRwySmIl9uI7eZCcTsqRVnTDfUr1JiXt7zonqNNm80PVYMs6pwaw7t97ec1AQJcsONjuXZyCMnu5g== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/protocol-http" "^1.1.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-flexible-checksums@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.363.0.tgz#99cd3e09183768ac378eae5c5f4e54189147921d" + integrity sha512-FBYmrMRX01uNximNN0WLgpf97GN4xNTLaKsDlkjYRWKJ+J97ICkvLG0FcSu7+SNCpCdJJBeQ5tRVOPVpUu6nmA== + dependencies: + "@aws-crypto/crc32" "3.0.0" + "@aws-crypto/crc32c" "3.0.0" + "@aws-sdk/types" "3.357.0" + "@smithy/is-array-buffer" "^1.0.1" + "@smithy/protocol-http" "^1.1.0" + "@smithy/types" "^1.1.0" + "@smithy/util-utf8" "^1.0.1" + tslib "^2.5.0" + +"@aws-sdk/middleware-host-header@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.363.0.tgz#3fc25569c1fdbb29ee7b95690d222743b9791210" + integrity sha512-FobpclDCf5Y1ueyJDmb9MqguAdPssNMlnqWQpujhYVABq69KHu73fSCWSauFPUrw7YOpV8kG1uagDF0POSxHzA== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/protocol-http" "^1.1.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-location-constraint@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.363.0.tgz#48c8a16698d7678578a5f06e0eb7f8118ec86f82" + integrity sha512-piNzpNNI/fChSGOZxcq/2msN2qFUSEAbhqs91zbcpv8CEPekVLc4W9laXCG764BEMyfG97ZU8MtzwHeMhELhBA== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-logger@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.363.0.tgz#64ebef9910802f9437cae8900e8825ca5141c9ed" + integrity sha512-SSGgthScYnFGTOw8EzbkvquqweFmvn7uJihkpFekbtBNGC/jGOGO+8ziHjTQ8t/iI/YKubEwv+LMi0f77HKSEg== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-recursion-detection@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.363.0.tgz#bd8b8010f5be5d7e90a97bf9e55a7980289b1600" + integrity sha512-MWD/57QgI/N7fG8rtzDTUdSqNpYohQfgj9XCFAoVeI/bU4usrkOrew43L4smJG4XrDxlNT8lSJlDtd64tuiUZA== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/protocol-http" "^1.1.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-sdk-s3@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.363.0.tgz#35e77ad14b6799b0be1c313d9c8b7ca0ad2f4fdb" + integrity sha512-npC8vLCero+vULizrK0QPjNanWbgH4A/2Llc1nO8N005uvUe7co6WglILF2W3guZrFk/0uGEdX67OnLxUD97pw== + dependencies: + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-arn-parser" "3.310.0" + "@smithy/protocol-http" "^1.1.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-sdk-sts@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.363.0.tgz#41b10aa8b8004bda9156cadde3b2302a84309e6a" + integrity sha512-1yy2Ac50FO8BrODaw5bPWvVrRhaVLqXTFH6iHB+dJLPUkwtY5zLM3Mp+9Ilm7kME+r7oIB1wuO6ZB1Lf4ZszIw== + dependencies: + "@aws-sdk/middleware-signing" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-signing@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.363.0.tgz#81067698e0566584f0ca30be56232758f69e2232" + integrity sha512-/7qia715pt9JKYIPDGu22WmdZxD8cfF/5xB+1kmILg7ZtjO0pPuTaCNJ7xiIuFd7Dn7JXp5lop08anX/GOhNRQ== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/property-provider" "^1.0.1" + "@smithy/protocol-http" "^1.1.0" + "@smithy/signature-v4" "^1.0.1" + "@smithy/types" "^1.1.0" + "@smithy/util-middleware" "^1.0.1" + tslib "^2.5.0" + +"@aws-sdk/middleware-ssec@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.363.0.tgz#9dde9e09660bcb6a0d39939d7f1ab043b93fefdb" + integrity sha512-pN+QN1rMShYpJnTJSCIYnNRhD0S8xSZsTn6ThgcO559Xiwz5LMHFOfOXUCEyxtbVW5kMHLUh3w101AMUKae99A== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-user-agent@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.363.0.tgz#a75a7ca5c791a68d750736c87b968b54d394443d" + integrity sha512-ri8YaQvXP6odteVTMfxPqFR26Q0h9ejtqhUDv47P34FaKXedEM4nC6ix6o+5FEYj6l8syGyktftZ5O70NoEhug== + dependencies: + "@aws-sdk/types" "3.357.0" + "@aws-sdk/util-endpoints" "3.357.0" + "@smithy/protocol-http" "^1.1.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/signature-v4-multi-region@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.363.0.tgz#7c64ba8a6af6f52f73ef849d4fcdd102f63ad606" + integrity sha512-iWamQSpaBKg88LKuiUq8xO/7iyxJ+ORkA3qDhAwUqyTJOg87ma47yFf4ycCKqINnflc3AIGLGzBHnkBc4cMF5g== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/protocol-http" "^1.1.0" + "@smithy/signature-v4" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/token-providers@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.363.0.tgz#c211ed6db62620c46194506db6d785f5c36aedc5" + integrity sha512-6+0aJ1zugNgsMmhTtW2LBWxOVSaXCUk2q3xyTchSXkNzallYaRiZMRkieW+pKNntnu0g5H1T0zyfCO0tbXwxEA== + dependencies: + "@aws-sdk/client-sso-oidc" "3.363.0" + "@aws-sdk/types" "3.357.0" + "@smithy/property-provider" "^1.0.1" + "@smithy/shared-ini-file-loader" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/types@3.357.0", "@aws-sdk/types@^3.222.0": + version "3.357.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.357.0.tgz#8491da71a4291cc2661c26a75089e86532b6a3b5" + integrity sha512-/riCRaXg3p71BeWnShrai0y0QTdXcouPSM0Cn1olZbzTf7s71aLEewrc96qFrL70XhY4XvnxMpqQh+r43XIL3g== + dependencies: + tslib "^2.5.0" + +"@aws-sdk/util-arn-parser@3.310.0": + version "3.310.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-arn-parser/-/util-arn-parser-3.310.0.tgz#861ff8810851be52a320ec9e4786f15b5fc74fba" + integrity sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA== + dependencies: + tslib "^2.5.0" + +"@aws-sdk/util-buffer-from@3.310.0": + version "3.310.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-buffer-from/-/util-buffer-from-3.310.0.tgz#7a72cb965984d3c6a7e256ae6cf1621f52e54a57" + integrity sha512-i6LVeXFtGih5Zs8enLrt+ExXY92QV25jtEnTKHsmlFqFAuL3VBeod6boeMXkN2p9lbSVVQ1sAOOYZOHYbYkntw== + dependencies: + "@aws-sdk/is-array-buffer" "3.310.0" + tslib "^2.5.0" + +"@aws-sdk/util-endpoints@3.357.0": + version "3.357.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.357.0.tgz#eaa7b4481bbd9fc8f13412b308ba4129d8fa2004" + integrity sha512-XHKyS5JClT9su9hDif715jpZiWHQF9gKZXER8tW0gOizU3R9cyWc9EsJ2BRhFNhi7nt/JF/CLUEc5qDx3ETbUw== + dependencies: + "@aws-sdk/types" "3.357.0" + tslib "^2.5.0" + +"@aws-sdk/util-locate-window@^3.0.0": + version "3.310.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz#b071baf050301adee89051032bd4139bba32cc40" + integrity sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w== + dependencies: + tslib "^2.5.0" + +"@aws-sdk/util-user-agent-browser@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.363.0.tgz#6f0655976f4f5889d6f0abed6c6cdc665cab524f" + integrity sha512-fk9ymBUIYbxiGm99Cn+kAAXmvMCWTf/cHAcB79oCXV4ELXdPa9lN5xQhZRFNxLUeXG4OAMEuCAUUuZEj8Fnc1Q== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/types" "^1.1.0" + bowser "^2.11.0" + tslib "^2.5.0" + +"@aws-sdk/util-user-agent-node@3.363.0": + version "3.363.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.363.0.tgz#9df26188a3d22694b4d06f5f40c489cb22fddb48" + integrity sha512-Fli/dvgGA9hdnQUrYb1//wNSFlK2jAfdJcfNXA6SeBYzSeH5pVGYF4kXF0FCdnMA3Fef+Zn1zAP/hw9v8VJHWQ== + dependencies: + "@aws-sdk/types" "3.357.0" + "@smithy/node-config-provider" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@aws-sdk/util-utf8-browser@^3.0.0": + version "3.259.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff" + integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw== + dependencies: + tslib "^2.3.1" + +"@aws-sdk/util-utf8@3.310.0": + version "3.310.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8/-/util-utf8-3.310.0.tgz#4a7b9dcebb88e830d3811aeb21e9a6df4273afb4" + integrity sha512-DnLfFT8uCO22uOJc0pt0DsSNau1GTisngBCDw8jQuWT5CqogMJu4b/uXmwEqfj8B3GX6Xsz8zOd6JpRlPftQoA== + dependencies: + "@aws-sdk/util-buffer-from" "3.310.0" + tslib "^2.5.0" + +"@aws-sdk/xml-builder@3.310.0": + version "3.310.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.310.0.tgz#f0236f2103b438d16117e0939a6305ad69b7ff76" + integrity sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw== + dependencies: + tslib "^2.5.0" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.22.5": version "7.22.5" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz" @@ -1032,7 +1712,7 @@ "@mapbox/node-pre-gyp@^1.0.10": version "1.0.10" - resolved "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c" integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA== dependencies: detect-libc "^2.0.0" @@ -1490,6 +2170,390 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@smithy/abort-controller@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-1.0.1.tgz#cfccff9200091bbbaa76a1b9c115978a4e49bae3" + integrity sha512-An6irzp9NCji2JtJHhrEFlDbxLwHd6c6Y9fq3ZeomyUR8BIXlGXVTxsemUSZVVgOq3166iYbYs/CrPAmgRSFLw== + dependencies: + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/config-resolver@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-1.0.1.tgz#da1c9f13f485e7cbb46e8aa62fe31c98deb6c403" + integrity sha512-quj0xUiEVG/UHfY82EtthR/+S5/17p3IxXArC3NFSNqryMobWbG9oWgJy2s2cgUSVZLzxevjKKvxrilK7JEDaA== + dependencies: + "@smithy/types" "^1.1.0" + "@smithy/util-config-provider" "^1.0.1" + "@smithy/util-middleware" "^1.0.1" + tslib "^2.5.0" + +"@smithy/credential-provider-imds@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-1.0.1.tgz#650b0f1d839e65accf9d5d20e216b61eb17c8f87" + integrity sha512-hkRJoxVCh4CEt1zYOBElE+G/MV6lyx3g68hSJpesM4pwMT/bzEVo5E5XzXY+6dVq8yszeatWKbFuqCCBQte8tg== + dependencies: + "@smithy/node-config-provider" "^1.0.1" + "@smithy/property-provider" "^1.0.1" + "@smithy/types" "^1.1.0" + "@smithy/url-parser" "^1.0.1" + tslib "^2.5.0" + +"@smithy/eventstream-codec@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-1.0.1.tgz#d35b29c501a39a7025be74f650f50dfe84471b85" + integrity sha512-cpcTXQEOEs2wEvIyxW/iTHJ2m0RVqoEOTjjWEXD6SY8Gcs3FCFP6E8MXadC098tdH5ctMIUXc8POXyMpxzGnjw== + dependencies: + "@aws-crypto/crc32" "3.0.0" + "@smithy/types" "^1.1.0" + "@smithy/util-hex-encoding" "^1.0.1" + tslib "^2.5.0" + +"@smithy/eventstream-serde-browser@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-1.0.1.tgz#d03e5262f6444708bf8313ab0e08179ab2718b0b" + integrity sha512-oc8vxe+AU2RzvXH/Ehh0TzM/Nsw3I3ywu7V3qaCzqdkBIntAwK9JGZqcSDsqTK0WxZKBRgFIEwopcuZ2slVnFQ== + dependencies: + "@smithy/eventstream-serde-universal" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/eventstream-serde-config-resolver@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-1.0.1.tgz#8e18dbca8874481ad3de5047a42e20eb77a5fa1b" + integrity sha512-TJwaXima0djnNY819utO1j93qZHaheFH1bhHxBkMrImtEOuXY48Tjma/L2m8swkIq8dy8jFC9hrYOkD0eYHkFA== + dependencies: + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/eventstream-serde-node@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-1.0.1.tgz#5765af12cadcde7fcc75db1c161f51c50adb1caf" + integrity sha512-JEj8w7IRs4l+kcwKxbv3pNuu8n7ORC4pMFrIOrM4rERzrRnI7vMNTRzvAPGYA53rqm/Y9tBA9dw4C+H6hLXcsA== + dependencies: + "@smithy/eventstream-serde-universal" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/eventstream-serde-universal@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-1.0.1.tgz#cb19a8381986a83b6d2c1ca0e72466140e0dfaa7" + integrity sha512-c6m9DH7m6D2S93dof4wSxysaGSQdauO20TNcSePzrgHd4rkTnz5pqZ1a7Pt22q2SKf09SvTugq5cV2Sy4r8zHw== + dependencies: + "@smithy/eventstream-codec" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/fetch-http-handler@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-1.0.1.tgz#0326ed6f4165a40a1979ed990f633c640846c4de" + integrity sha512-/e2A8eOMk4FVZBQ0o6uF/ttLtFZcmsK5MIwDu1UE3crM4pCAIP19Ul8U9rdLlHhIu81X4AcJmSw55RDSpVRL/w== + dependencies: + "@smithy/protocol-http" "^1.1.0" + "@smithy/querystring-builder" "^1.0.1" + "@smithy/types" "^1.1.0" + "@smithy/util-base64" "^1.0.1" + tslib "^2.5.0" + +"@smithy/hash-node@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-1.0.1.tgz#9cffefd78f74a99d7f0d99f19596be1a163f70b1" + integrity sha512-eCz08BySBcOjVObjbRAS/XMKUGY4ujnuS+GoWeEpzpCSKDnO8/YQ0rStRt4C0llRmhApizYc1tK9DiJwfvXcBg== + dependencies: + "@smithy/types" "^1.1.0" + "@smithy/util-buffer-from" "^1.0.1" + "@smithy/util-utf8" "^1.0.1" + tslib "^2.5.0" + +"@smithy/invalid-dependency@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-1.0.1.tgz#1dde6b71b91e29e3f347a56e9d246c0c48a81748" + integrity sha512-kib63GFlAzRn/wf8M0cRWrZA1cyOy5IvpTkLavCY782DPFMP0EaEeD6VrlNIOvD6ncf7uCJ68HqckhwK1qLT3g== + dependencies: + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/is-array-buffer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-1.0.1.tgz#42997d8321234438c141089120b5d3c9d68b0400" + integrity sha512-fHSTW70gANnzPYWNDcWkPXpp+QMbHhKozbQm/+Denkhp4gwSiPuAovWZRpJa9sXO+Q4dOnNzYN2max1vTCEroA== + dependencies: + tslib "^2.5.0" + +"@smithy/middleware-content-length@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-1.0.1.tgz#78747dfc7079e542c04675bb3ab1370c35511f7b" + integrity sha512-vWWigayk5i2cFp9xPX5vdzHyK+P0t/xZ3Ovp4Ss+c8JQ1Hlq2kpJZVWtTKsmdfND5rVo5lu0kD5wgAMUCcmuhw== + dependencies: + "@smithy/protocol-http" "^1.1.0" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/middleware-endpoint@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-1.0.1.tgz#c1d047bd9de815cd08c5c9de7ed026754f68ac2c" + integrity sha512-XEHPq73PPm0sXul//5MRC8JKDwHTaNjV3myd9FJ5YoUT+QMJ27gqiwwAMVASJ6vC4ELHzgQdmoTZxVX83Jx17w== + dependencies: + "@smithy/middleware-serde" "^1.0.1" + "@smithy/types" "^1.1.0" + "@smithy/url-parser" "^1.0.1" + "@smithy/util-middleware" "^1.0.1" + tslib "^2.5.0" + +"@smithy/middleware-retry@^1.0.1", "@smithy/middleware-retry@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-1.0.2.tgz#2033f82fdbd210efe70f5a35b761b13fe570d7b2" + integrity sha512-Osj+XsqJ67RuX1MLc3+7LDtlRz8eNVqr/Pim9yPAjRa03Xberu6ST3a3oV3NqRpcUgMTifxuaKVIciuPE3rTWA== + dependencies: + "@smithy/protocol-http" "^1.1.0" + "@smithy/service-error-classification" "^1.0.1" + "@smithy/types" "^1.1.0" + "@smithy/util-middleware" "^1.0.1" + "@smithy/util-retry" "^1.0.2" + tslib "^2.5.0" + uuid "^8.3.2" + +"@smithy/middleware-serde@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-1.0.1.tgz#b2f0e13abe3d0becb9c5b19d751fbb4b28bd9b1d" + integrity sha512-bn5lWk8UUeXFCQfkrNErz5SbeNd+2hgYegHMLsOLPt4URDIsyREar6wMsdsR+8UCdgR5s8udG3Zalgc7puizIQ== + dependencies: + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/middleware-stack@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-1.0.1.tgz#cfa8de79ca8bc09fc3c266a0e0241c639b571870" + integrity sha512-T6+gsAO1JYamOJqmORCrByDeQ/NB+ggjHb33UDOgdX4xIjXz/FB/3UqHgQu6PL1cSFrK+i4oteDIwqARDs/Szw== + dependencies: + tslib "^2.5.0" + +"@smithy/node-config-provider@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-1.0.1.tgz#c9b3c1f49a5238b398ad7ff1f2df28315672853f" + integrity sha512-FRxifH/J2SgOaVLihIqBFuGhiHR/NfzbZYp5nYO7BGgT/gc/f9nAuuRJcEy/hwO3aI6ThyG5apH4tGec6A2sCw== + dependencies: + "@smithy/property-provider" "^1.0.1" + "@smithy/shared-ini-file-loader" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/node-http-handler@^1.0.1", "@smithy/node-http-handler@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-1.0.2.tgz#fe27a3a5d83874a23d24c29cd2bf0258a5e4730b" + integrity sha512-PzPrGRSt3kNuruLCeR4ffJp57ZLVnIukMXVL3Ppr65ZoxiE+HBsOVAa/Z/T+4HzjCM6RaXnnmB8YKfsDjlb0iA== + dependencies: + "@smithy/abort-controller" "^1.0.1" + "@smithy/protocol-http" "^1.1.0" + "@smithy/querystring-builder" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/property-provider@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-1.0.1.tgz#b4c2f41313fcfe33d64f6198f91fc9edd96dc28d" + integrity sha512-3EG/61Ls1MrgEaafpltXBJHSqFPqmTzEX7QKO7lOEHuYGmGYzZ08t1SsTgd1vM74z0IihoZyGPynZ7WmXKvTeg== + dependencies: + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/protocol-http@^1.0.1", "@smithy/protocol-http@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-1.1.0.tgz#caf22e01cb825d7490a4915e03d6fa64954ff535" + integrity sha512-H5y/kZOqfJSqRkwtcAoVbqONmhdXwSgYNJ1Glk5Ry8qlhVVy5qUzD9EklaCH8/XLnoCsLO/F/Giee8MIvaBRkg== + dependencies: + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/querystring-builder@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-1.0.1.tgz#c8e9ca45c072763ad34b34a4aaf6a85eb37eafd3" + integrity sha512-J5Tzkw1PMtu01h6wl+tlN5vsyROmS6/z5lEfNlLo/L4ELHeVkQ4Q0PEIjDddPLfjVLCm8biQTESE5GCMixSRNQ== + dependencies: + "@smithy/types" "^1.1.0" + "@smithy/util-uri-escape" "^1.0.1" + tslib "^2.5.0" + +"@smithy/querystring-parser@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-1.0.1.tgz#bf5e326debaecb9e1db44972f1eb87d64e8915e8" + integrity sha512-zauxdMc3cwxoLitI5DZqH7xN6Fk0mwRxrUMAETbav2j6Se2U0UGak/55rZcDg2yGzOURaLYi5iOm1gHr98P+Bw== + dependencies: + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/service-error-classification@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-1.0.1.tgz#a8528087b5ac02ef7e0cd2190bed8399b78efa47" + integrity sha512-EcFVOHFv4YZHUrJ6161tpPKXNlQsTAQKoKorODxuOQW1my14mgoyiiMXrlnSMaYRF//oaONYfFOQ2EMAUTC5DQ== + +"@smithy/shared-ini-file-loader@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-1.0.1.tgz#6bc72721e0b1148b199bd2bb21b4d5d3083534bb" + integrity sha512-EztziuIPoNronENGqh+MWVKJErA4rJpaPzJCPukzBeEoG2USka0/q4B5Mr/1zszOnrb49fPNh4u3u5LfiH7QzA== + dependencies: + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/signature-v4@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-1.0.1.tgz#03e9d8e3fd5d4f449fc3c188402f5655231d91aa" + integrity sha512-2D69je14ou1vBTnAQeysSK4QVMm0j3WHS3MDg/DnHnFFcXRCzVl/xAARO7POD8+fpi4tMFPs8Z4hzo1Zw40L0Q== + dependencies: + "@smithy/eventstream-codec" "^1.0.1" + "@smithy/is-array-buffer" "^1.0.1" + "@smithy/types" "^1.1.0" + "@smithy/util-hex-encoding" "^1.0.1" + "@smithy/util-middleware" "^1.0.1" + "@smithy/util-uri-escape" "^1.0.1" + "@smithy/util-utf8" "^1.0.1" + tslib "^2.5.0" + +"@smithy/smithy-client@^1.0.2", "@smithy/smithy-client@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-1.0.3.tgz#f31bf64fc4a21fc42171120635e6af2b58dabc22" + integrity sha512-Wh1mNP/1yUZK0uYkgCQ6NMxpBT3Fmc45TMdUfOlH1xD2zGYL7U4yDHFOhEZdi/suyjaelFobXB2p9pPIw6LjRQ== + dependencies: + "@smithy/middleware-stack" "^1.0.1" + "@smithy/types" "^1.1.0" + "@smithy/util-stream" "^1.0.1" + tslib "^2.5.0" + +"@smithy/types@^1.0.0", "@smithy/types@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-1.1.0.tgz#f30a23202c97634cca5c1ac955a9bf149c955226" + integrity sha512-KzmvisMmuwD2jZXuC9e65JrgsZM97y5NpDU7g347oB+Q+xQLU6hQZ5zFNNbEfwwOJHoOvEVTna+dk1h/lW7alw== + dependencies: + tslib "^2.5.0" + +"@smithy/url-parser@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-1.0.1.tgz#a7e52ebb4c8c1d19aa47397b7d78ebcdf767013a" + integrity sha512-33vWEtE6HzmwjEcEb4I58XMLRAchwPS93YhfDyXAXr1jwDCzfXmMayQwwpyW847rpWj0XJimxqia8q0z+k/ybw== + dependencies: + "@smithy/querystring-parser" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/util-base64@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-1.0.1.tgz#69f682a542ca57ffb732da6f2e9309d238d52d84" + integrity sha512-rJcpRi/yUi6TyCEkjdTH86/ExBuKlfctEXhG9/4gMJ3/cnPcHJJnr0mQ9evSEO+3DbpT/Nxq90bcTBdTIAmCig== + dependencies: + "@smithy/util-buffer-from" "^1.0.1" + tslib "^2.5.0" + +"@smithy/util-body-length-browser@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-browser/-/util-body-length-browser-1.0.1.tgz#42b3042a4a58119aa97e9b85c1f7bb11dcc3b472" + integrity sha512-Pdp744fmF7E1NWoSb7256Anhm8eYoCubvosdMwXzOnHuPRVbDa15pKUz2027K3+jrfGpXo1r+MnDerajME1Osw== + dependencies: + tslib "^2.5.0" + +"@smithy/util-body-length-node@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-1.0.1.tgz#7909b05c8d5963ce44b1fc424bb1cdda7615af94" + integrity sha512-4PIHjDFwG07SNensAiVq/CJmubEVuwclWSYOTNtzBNTvxOeGLznvygkGYgPzS3erByT8C4S9JvnLYgtrsVV3nQ== + dependencies: + tslib "^2.5.0" + +"@smithy/util-buffer-from@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-1.0.1.tgz#ec73eb769b246062ae86d037c2f3d54868a7c803" + integrity sha512-363N7Wq0ceUgE5lLe6kaR6GlJs2/m4r9V6bRMfIszb6P1FZbbRRM2FQYUWWPFSsRymm9mJL18b3fjiVsIvhDGg== + dependencies: + "@smithy/is-array-buffer" "^1.0.1" + tslib "^2.5.0" + +"@smithy/util-config-provider@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-config-provider/-/util-config-provider-1.0.1.tgz#597d4f9a0bc9eab62c0d082b8e0772f92d85f99c" + integrity sha512-4Qy38Oy5/q43MpTwCLV1P+7NeaOp4W2etQDxMjgEeRlOyGGNlgttn0syi4g2rVSukFVqQ6FbeRs5xbnFmS6kaQ== + dependencies: + tslib "^2.5.0" + +"@smithy/util-defaults-mode-browser@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-1.0.1.tgz#609074d664dacb7fe6567d8fc259a85da2d4d262" + integrity sha512-/9ObwNch4Z/NJYfkO4AvqBWku60Ju+c2Ck32toPOLmWe/V6eI9FLn8C1abri+GxDRCkLIqvkaWU1lgZ3nWZIIw== + dependencies: + "@smithy/property-provider" "^1.0.1" + "@smithy/types" "^1.1.0" + bowser "^2.11.0" + tslib "^2.5.0" + +"@smithy/util-defaults-mode-node@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-1.0.1.tgz#5efe0bc575ec2253a4723d05a6f1fd28a567996e" + integrity sha512-XQM3KvqRLgv7bwAzVkXTITkOmcOINoG9icJiGT8FA0zV35lY5UvyIsg5kHw01xigQS8ufa/33AwG3ZoXip+V5g== + dependencies: + "@smithy/config-resolver" "^1.0.1" + "@smithy/credential-provider-imds" "^1.0.1" + "@smithy/node-config-provider" "^1.0.1" + "@smithy/property-provider" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + +"@smithy/util-hex-encoding@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-1.0.1.tgz#78778f664fa2624b2892d73e82df29b6d8e02380" + integrity sha512-FPTtMz/t02/rbfq5Pdll/TWUYP+GVFLCQNr+DgifrLzVRU0g8rdRjyFpDh8nPTdkDDusTTo9P1bepAYj68s0eA== + dependencies: + tslib "^2.5.0" + +"@smithy/util-middleware@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-1.0.1.tgz#8c1b04e9eb60e135a7083fc3ff729f969cd38d6a" + integrity sha512-u9akN3Zmbr0vZH4F+2iehG7cFg+3fvDfnvS/hhsXH4UHuhqiQ+ADefibnLzPoz1pooY7rvwaQ/TVHyJmZHdLdQ== + dependencies: + tslib "^2.5.0" + +"@smithy/util-retry@^1.0.1", "@smithy/util-retry@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-1.0.2.tgz#404ab400d3a1027acd3649b031f4108c148f10ba" + integrity sha512-LqzAy1QzeAHpSZpsd2LtKZRbco7F5gF+Zpoa4TuuFq9f+CGmH6OuTCIN3I13LPEBa4zs2AgvGnXljvMbUw5WGw== + dependencies: + "@smithy/service-error-classification" "^1.0.1" + tslib "^2.5.0" + +"@smithy/util-stream@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-1.0.1.tgz#3a8ec036ab429a150f2e36fb8a4b947255a7a258" + integrity sha512-4aBCIz35aZAnt2Rbq341KrnUzGhWv2/Zu8HouJqYLvSWCzlrvsNCGlXP4e70Kjzcw8hSuuCNtdUICwQ5qUWLxg== + dependencies: + "@smithy/fetch-http-handler" "^1.0.1" + "@smithy/node-http-handler" "^1.0.2" + "@smithy/types" "^1.1.0" + "@smithy/util-base64" "^1.0.1" + "@smithy/util-buffer-from" "^1.0.1" + "@smithy/util-hex-encoding" "^1.0.1" + "@smithy/util-utf8" "^1.0.1" + tslib "^2.5.0" + +"@smithy/util-uri-escape@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-1.0.1.tgz#16422dc996767c459b12bf045a942e4044a32952" + integrity sha512-IJUrRnXKEIc+PKnU1XzTsIENVR+60jUDPBP3iWX/EvuuT3Xfob47x1FGUe2c3yMXNuU6ax8VDk27hL5LKNoehQ== + dependencies: + tslib "^2.5.0" + +"@smithy/util-utf8@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-1.0.1.tgz#6ce31e1f165212b1060aae11f7de4fe06ce8533a" + integrity sha512-iX6XHpjh4DFEUIBSKp2tjy3pYnLQMsJ62zYi1BVAC0kobE6p8AVpiZnxsU3ZkgQatAsUaEspFHUZ7CL7oSqaPQ== + dependencies: + "@smithy/util-buffer-from" "^1.0.1" + tslib "^2.5.0" + +"@smithy/util-waiter@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-1.0.1.tgz#d0ef960684f0755028abd02b8866e9b377363170" + integrity sha512-dsn8O0s3pFIgxFzySLe1dv0w4tEQizEP6UqbgZ4r/Kar4n8pSdrPi6DJg8BzXwkwEIZpMtV4/nhSeGZ7HksDXA== + dependencies: + "@smithy/abort-controller" "^1.0.1" + "@smithy/types" "^1.1.0" + tslib "^2.5.0" + "@ts-morph/common@~0.17.0": version "0.17.0" resolved "https://registry.npmjs.org/@ts-morph/common/-/common-0.17.0.tgz" @@ -1520,7 +2584,7 @@ resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@types/accepts@^1.3.5": +"@types/accepts@*", "@types/accepts@^1.3.5": version "1.3.5" resolved "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz" integrity sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ== @@ -1582,11 +2646,26 @@ dependencies: "@types/node" "*" +"@types/content-disposition@*": + version "0.5.5" + resolved "https://registry.yarnpkg.com/@types/content-disposition/-/content-disposition-0.5.5.tgz#650820e95de346e1f84e30667d168c8fd25aa6e3" + integrity sha512-v6LCdKfK6BwcqMo+wYW05rLS12S0ZO0Fl4w1h4aaZMD7bqT3gVUns6FvLJKGZHQmYn3SX55JWGpziwJRwVgutA== + "@types/cookiejar@*": version "2.1.2" resolved "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz" integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== +"@types/cookies@*": + version "0.7.7" + resolved "https://registry.yarnpkg.com/@types/cookies/-/cookies-0.7.7.tgz#7a92453d1d16389c05a5301eef566f34946cfd81" + integrity sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA== + dependencies: + "@types/connect" "*" + "@types/express" "*" + "@types/keygrip" "*" + "@types/node" "*" + "@types/cors@2.8.12": version "2.8.12" resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz" @@ -1680,6 +2759,26 @@ dependencies: "@types/node" "*" +"@types/graphql-upload@^8.0.12": + version "8.0.12" + resolved "https://registry.yarnpkg.com/@types/graphql-upload/-/graphql-upload-8.0.12.tgz#224738b8885bad8d50fb690b67bbe10bbcdef032" + integrity sha512-M0ZPZqNUzKNB16q5woEzgG/Q8DjICV80K7JvDSRnDmDFfrRdfFX/n6PbmqAN7gCzECcHVnw1gk6N4Cg0FwxCqA== + dependencies: + "@types/express" "*" + "@types/koa" "*" + fs-capacitor "^8.0.0" + graphql "0.13.1 - 16" + +"@types/http-assert@*": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@types/http-assert/-/http-assert-1.5.3.tgz#ef8e3d1a8d46c387f04ab0f2e8ab8cb0c5078661" + integrity sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA== + +"@types/http-errors@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" + integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz" @@ -1726,6 +2825,58 @@ dependencies: "@types/node" "*" +"@types/keygrip@*": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.2.tgz#513abfd256d7ad0bf1ee1873606317b33b1b2a72" + integrity sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw== + +"@types/koa-compose@*": + version "3.2.5" + resolved "https://registry.yarnpkg.com/@types/koa-compose/-/koa-compose-3.2.5.tgz#85eb2e80ac50be95f37ccf8c407c09bbe3468e9d" + integrity sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ== + dependencies: + "@types/koa" "*" + +"@types/koa@*": + version "2.13.6" + resolved "https://registry.yarnpkg.com/@types/koa/-/koa-2.13.6.tgz#6dc14e727baf397310aa6f414ebe5d144983af42" + integrity sha512-diYUfp/GqfWBAiwxHtYJ/FQYIXhlEhlyaU7lB/bWQrx4Il9lCET5UwpFy3StOAohfsxxvEQ11qIJgT1j2tfBvw== + dependencies: + "@types/accepts" "*" + "@types/content-disposition" "*" + "@types/cookies" "*" + "@types/http-assert" "*" + "@types/http-errors" "*" + "@types/keygrip" "*" + "@types/koa-compose" "*" + "@types/node" "*" + +"@types/lodash.camelcase@^4.3.7": + version "4.3.7" + resolved "https://registry.yarnpkg.com/@types/lodash.camelcase/-/lodash.camelcase-4.3.7.tgz#b0a06a216542335c0326c0d2fbad3f121b1f29a7" + integrity sha512-Nfi6jpo9vuEOSIJP+mpbTezKyEt75DQlbwjiDvs/JctWkbnHDoyQo5lWqdvgNiJmVUjcmkfvlrvSEgJYvurOKg== + dependencies: + "@types/lodash" "*" + +"@types/lodash.isobject@^3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@types/lodash.isobject/-/lodash.isobject-3.0.7.tgz#8a37beea56512f0ae86f8d48ea01e2ea9b79c185" + integrity sha512-nuC74gk3hEmpY4Jq5xIfQc9uoWg2ozVIqS7OwS9xPncFr+d6ULBDpBBOcSaJKm2euKANHBeRGNEaHMAddIzSfA== + dependencies: + "@types/lodash" "*" + +"@types/lodash.kebabcase@^4.1.7": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/lodash.kebabcase/-/lodash.kebabcase-4.1.7.tgz#eb2d1162c669ecbc77f9912a31e952563848deff" + integrity sha512-qzrcpK5uiADZ9OyZaegalM0b9Y3WetoBQ04RAtP3xZFGC5ul1UxmbjZ3j6suCh0BDkvgQmoMh8t5e9cVrdJYMw== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.195" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632" + integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg== + "@types/long@^4.0.0": version "4.0.2" resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" @@ -2151,7 +3302,7 @@ abbrev@1: version "1.1.1" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== accepts@^1.3.5, accepts@~1.3.8: @@ -2189,7 +3340,7 @@ add@^2.0.6: agent-base@6: version "6.0.2" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" @@ -2389,7 +3540,7 @@ append-field@^1.0.0: "aproba@^1.0.3 || ^2.0.0": version "2.0.0" - resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== archiver-utils@^2.1.0: @@ -2423,7 +3574,7 @@ archiver@5.3.1: are-we-there-yet@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== dependencies: delegates "^1.0.0" @@ -2586,7 +3737,7 @@ base64url@3.x.x: bcrypt@^5.1.0: version "5.1.0" - resolved "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.0.tgz" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.1.0.tgz#bbb27665dbc400480a524d8991ac7434e8529e17" integrity sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q== dependencies: "@mapbox/node-pre-gyp" "^1.0.10" @@ -2642,6 +3793,11 @@ body-parser@1.20.2, body-parser@^1.19.0, body-parser@^1.20.0: type-is "~1.6.18" unpipe "1.0.0" +bowser@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" + integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== + boxen@5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz" @@ -2725,6 +3881,13 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +busboy@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b" + integrity sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw== + dependencies: + dicer "0.3.0" + busboy@^1.0.0: version "1.6.0" resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz" @@ -2825,9 +3988,14 @@ chokidar@3.5.3, chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + chownr@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== chrome-trace-event@^1.0.2: @@ -2951,16 +4119,32 @@ color-name@1.1.3: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@~1.1.4: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + color-support@^1.1.2: version "1.1.3" - resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== +color@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== + dependencies: + color-convert "^2.0.1" + color-string "^1.9.0" + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -3020,7 +4204,7 @@ consola@^2.15.0: console-control-strings@^1.0.0, console-control-strings@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== content-disposition@0.5.4: @@ -3137,11 +4321,23 @@ debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: dependencies: ms "2.1.2" +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + dedent@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz" integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" @@ -3180,7 +4376,7 @@ delayed-stream@~1.0.0: delegates@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== depd@2.0.0: @@ -3188,14 +4384,19 @@ depd@2.0.0: resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + destroy@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-libc@^2.0.0: +detect-libc@^2.0.0, detect-libc@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== detect-newline@^3.0.0: @@ -3211,6 +4412,13 @@ dezalgo@^1.0.4: asap "^2.0.0" wrappy "1" +dicer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872" + integrity sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA== + dependencies: + streamsearch "0.1.2" + diff-sequences@^28.1.1: version "28.1.1" resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz" @@ -3515,6 +4723,11 @@ exit@^0.1.2: resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + expect@^28.0.0, expect@^28.1.3: version "28.1.3" resolved "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz" @@ -3613,6 +4826,13 @@ fast-write-atomic@0.2.1: resolved "https://registry.npmjs.org/fast-write-atomic/-/fast-write-atomic-0.2.1.tgz" integrity sha512-WvJe06IfNYlr+6cO3uQkdKdy3Cb1LlCJSF8zRs2eT8yuhdbSlR9nIt+TgQ92RUxiRrQm+/S7RARnMfCs5iuAjw== +fast-xml-parser@4.2.5: + version "4.2.5" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz#a6747a09296a6cb34f2ae634019bf1738f3b421f" + integrity sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g== + dependencies: + strnum "^1.0.5" + fastq@^1.6.0: version "1.15.0" resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz" @@ -3784,6 +5004,16 @@ fresh@0.5.2: resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== +fs-capacitor@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-6.2.0.tgz#fa79ac6576629163cb84561995602d8999afb7f5" + integrity sha512-nKcE1UduoSKX27NSZlg879LdQc94OtbOsEmKMN2MBNudXREvijRKx2GEBsTMTfws+BrbkJoEuynbGSVRSpauvw== + +fs-capacitor@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-8.0.0.tgz#a95cbcf58dd50750fe718a03ec051961ef4e61f4" + integrity sha512-+Lk6iSKajdGw+7XYxUkwIzreJ2G1JFlYOdnKJv5PzwFLVsoJYBpCuS7WPIUSNT1IbQaEWT1nhYU63Ud03DyzLA== + fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" @@ -3816,7 +5046,7 @@ fs-jetpack@5.1.0: fs-minipass@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== dependencies: minipass "^3.0.0" @@ -3843,7 +5073,7 @@ function-bind@^1.1.1: gauge@^3.0.0: version "3.0.2" - resolved "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== dependencies: aproba "^1.0.3 || ^2.0.0" @@ -3898,6 +5128,11 @@ get-stream@^6.0.0: resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== + glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -4016,11 +5251,26 @@ graphql-type-json@^0.3.2: resolved "https://registry.yarnpkg.com/graphql-type-json/-/graphql-type-json-0.3.2.tgz#f53a851dbfe07bd1c8157d24150064baab41e115" integrity sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg== +graphql-upload@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/graphql-upload/-/graphql-upload-13.0.0.tgz#1a255b64d3cbf3c9f9171fa62a8fb0b9b59bb1d9" + integrity sha512-YKhx8m/uOtKu4Y1UzBFJhbBGJTlk7k4CydlUUiNrtxnwZv0WigbRHP+DVhRNKt7u7DXOtcKZeYJlGtnMXvreXA== + dependencies: + busboy "^0.3.1" + fs-capacitor "^6.2.0" + http-errors "^1.8.1" + object-path "^0.11.8" + graphql-ws@5.13.1: version "5.13.1" resolved "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.13.1.tgz" integrity sha512-eiX7ES/ZQr0q7hSM5UBOEIFfaAUmAY9/CSDyAnsETuybByU7l/v46drRg9DQoTvVABEHp3QnrvwgTRMhqy7zxQ== +"graphql@0.13.1 - 16": + version "16.7.1" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.7.1.tgz#11475b74a7bff2aefd4691df52a0eca0abd9b642" + integrity sha512-DRYR9tf+UGU0KOsMcKAlXeFfX89UiiIZ0dRU3mR0yJfu6OjZqUcp68NnFLnqQU5RexygFoDy1EW+ccOYcPfmHg== + graphql@^16.6.0: version "16.6.0" resolved "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz" @@ -4048,7 +5298,7 @@ has-symbols@^1.0.3: has-unicode@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== has@^1.0.3: @@ -4092,6 +5342,17 @@ http-errors@2.0.0: statuses "2.0.1" toidentifier "1.0.1" +http-errors@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + http-proxy-agent@7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz" @@ -4110,7 +5371,7 @@ https-proxy-agent@7.0.0: https-proxy-agent@^5.0.0: version "5.0.1" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== dependencies: agent-base "6" @@ -4194,6 +5455,11 @@ ini@2.0.0: resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + inquirer@8.2.4: version "8.2.4" resolved "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz" @@ -4251,6 +5517,11 @@ is-arrayish@^0.2.1: resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" @@ -4925,6 +6196,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz" @@ -4940,11 +6216,21 @@ lodash.flatten@^4.4.0: resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz" integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== +lodash.isobject@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d" + integrity sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA== + lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g== + lodash.memoize@4.x: version "4.1.2" resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" @@ -5120,6 +6406,11 @@ mimic-fn@^2.1.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + min-indent@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" @@ -5146,14 +6437,14 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minipass@^3.0.0: version "3.3.6" - resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: yallist "^4.0.0" @@ -5165,7 +6456,7 @@ minipass@^4.2.4: minipass@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== "minipass@^5.0.0 || ^6.0.2": @@ -5175,12 +6466,17 @@ minipass@^5.0.0: minizlib@^2.1.1: version "2.1.2" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: minipass "^3.0.0" yallist "^4.0.0" +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@^0.5.4: version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" @@ -5226,6 +6522,11 @@ mute-stream@0.0.8: resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz" @@ -5251,6 +6552,13 @@ new-github-issue-url@0.2.1: resolved "https://registry.npmjs.org/new-github-issue-url/-/new-github-issue-url-0.2.1.tgz" integrity sha512-md4cGoxuT4T4d/HDOXbrUHkTKrp/vp+m3aOA7XXVYwNsUNMK49g3SQicTSeV5GIz/5QVGAeYRAOlyp9OvlgsYA== +node-abi@^3.3.0: + version "3.45.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.45.0.tgz#f568f163a3bfca5aacfce1fbeee1fa2cc98441f5" + integrity sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ== + dependencies: + semver "^7.3.5" + node-abort-controller@^3.0.1, node-abort-controller@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz" @@ -5258,9 +6566,14 @@ node-abort-controller@^3.0.1, node-abort-controller@^3.1.1: node-addon-api@^5.0.0: version "5.1.0" - resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== +node-addon-api@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76" + integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== + node-emoji@1.11.0: version "1.11.0" resolved "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz" @@ -5287,7 +6600,7 @@ node-releases@^2.0.12: nopt@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== dependencies: abbrev "1" @@ -5338,7 +6651,7 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: npmlog@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== dependencies: are-we-there-yet "^2.0.0" @@ -5361,6 +6674,11 @@ object-inspect@^1.9.0: resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-path@^0.11.8: + version "0.11.8" + resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.8.tgz#ed002c02bbdd0070b78a27455e8ae01fc14d4742" + integrity sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA== + on-finished@2.4.1: version "2.4.1" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" @@ -5649,6 +6967,24 @@ pluralize@8.0.0, pluralize@^8.0.0: resolved "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== +prebuild-install@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" + integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw== + dependencies: + detect-libc "^2.0.0" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^1.0.1" + node-abi "^3.3.0" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^4.0.0" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" @@ -5803,6 +7139,16 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + react-is@^18.0.0: version "18.2.0" resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" @@ -6023,6 +7369,13 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.5.0: + version "7.5.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" + integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== + dependencies: + lru-cache "^6.0.0" + send@0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" @@ -6061,7 +7414,7 @@ serve-static@1.15.0: set-blocking@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== setprototypeof@1.2.0: @@ -6077,6 +7430,20 @@ sha.js@^2.4.11: inherits "^2.0.1" safe-buffer "^5.0.1" +sharp@^0.32.1: + version "0.32.1" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.1.tgz#41aa0d0b2048b2e0ee453d9fcb14ec1f408390fe" + integrity sha512-kQTFtj7ldpUqSe8kDxoGLZc1rnMFU0AO2pqbX6pLy3b7Oj8ivJIdoKNwxHVQG2HN6XpHPJqCSM2nsma2gOXvOg== + dependencies: + color "^4.2.3" + detect-libc "^2.0.1" + node-addon-api "^6.1.0" + prebuild-install "^7.1.1" + semver "^7.5.0" + simple-get "^4.0.1" + tar-fs "^2.1.1" + tunnel-agent "^0.6.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -6112,6 +7479,27 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^4.0.0, simple-get@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== + dependencies: + decompress-response "^6.0.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" @@ -6200,6 +7588,16 @@ statuses@2.0.1: resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +"statuses@>= 1.5.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +streamsearch@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" + integrity sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA== + streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" @@ -6270,6 +7668,11 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + strip-outer@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz" @@ -6277,6 +7680,11 @@ strip-outer@^1.0.1: dependencies: escape-string-regexp "^1.0.2" +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + subscriptions-transport-ws@0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz" @@ -6361,7 +7769,17 @@ tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1: resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -tar-stream@^2.2.0: +tar-fs@^2.0.0, tar-fs@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4, tar-stream@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== @@ -6374,7 +7792,7 @@ tar-stream@^2.2.0: tar@^6.1.11: version "6.1.15" - resolved "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.15.tgz#c9738b0b98845a3b344d334b8fa3041aaba53a69" integrity sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A== dependencies: chownr "^2.0.0" @@ -6615,11 +8033,16 @@ tslib@2.5.3, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz" integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== -tslib@^1.8.1: +tslib@^1.11.1, tslib@^1.8.1: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.3.1, tslib@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" + integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" @@ -6627,6 +8050,13 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" @@ -6664,6 +8094,11 @@ type-fest@^0.8.0, type-fest@^0.8.1: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.12.0.tgz#4ce26edc1ccc59fc171e495887ef391fe1f5280e" + integrity sha512-qj9wWsnFvVEMUDbESiilKeXeHL7FwwiFcogfhfyjmvT968RXSvnl23f1JOClTHYItsi7o501C/7qVllscUP3oA== + type-is@^1.6.4, type-is@~1.6.18: version "1.6.18" resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" @@ -6746,6 +8181,11 @@ uuid@^3.3.2: resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" @@ -6877,7 +8317,7 @@ which@^2.0.1: wide-align@^1.1.2: version "1.1.5" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: string-width "^1.0.2 || 2 || 3 || 4"