diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 22fe3f6f..468582b7 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,7 +1,19 @@
-## 완료한 기능 혹은 수정 기능
+## 🚀 완료한 기능 혹은 수정 기능
-## 고민과 해결 과정
-## 스크린샷
+
-## 테스트 결과(커버리지/테스트 결과)
\ No newline at end of file
+## 💡 고민과 해결 과정
+### `배경`
+
+### `고민`
+
+### `해결과정`
+
+
+
+## 📸 스크린샷
+
+
+
+## ✅ 테스트 결과(커버리지/테스트 결과)
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..a30d2ef2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+# 디폴트 무시된 파일
+/.idea/shelf/
+/.idea/workspace.xml
+# 에디터 기반 HTTP 클라이언트 요청
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+
+/.idea
diff --git a/server/.dockerignore b/server/.dockerignore
new file mode 100644
index 00000000..0955eaef
--- /dev/null
+++ b/server/.dockerignore
@@ -0,0 +1,4 @@
+.gitignore
+Dockerfile
+node_modules
+dist
\ No newline at end of file
diff --git a/server/.eslintrc.js b/server/.eslintrc.js
new file mode 100644
index 00000000..259de13c
--- /dev/null
+++ b/server/.eslintrc.js
@@ -0,0 +1,25 @@
+module.exports = {
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ project: 'tsconfig.json',
+ tsconfigRootDir: __dirname,
+ sourceType: 'module',
+ },
+ plugins: ['@typescript-eslint/eslint-plugin'],
+ extends: [
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:prettier/recommended',
+ ],
+ root: true,
+ env: {
+ node: true,
+ jest: true,
+ },
+ ignorePatterns: ['.eslintrc.js'],
+ rules: {
+ '@typescript-eslint/interface-name-prefix': 'off',
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
+ '@typescript-eslint/no-explicit-any': 'off',
+ },
+};
diff --git a/server/.gitignore b/server/.gitignore
new file mode 100644
index 00000000..eca986df
--- /dev/null
+++ b/server/.gitignore
@@ -0,0 +1,37 @@
+# compiled output
+/dist
+/node_modules
+
+# Logs
+logs
+*.log
+npm-debug.log*
+pnpm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# OS
+.DS_Store
+
+# Tests
+/coverage
+/.nyc_output
+
+# IDEs and editors
+/.idea
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# IDE - VSCode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/extensions.json
+
+.env
+postgres-data
\ No newline at end of file
diff --git a/server/.prettierrc b/server/.prettierrc
new file mode 100644
index 00000000..dcb72794
--- /dev/null
+++ b/server/.prettierrc
@@ -0,0 +1,4 @@
+{
+ "singleQuote": true,
+ "trailingComma": "all"
+}
\ No newline at end of file
diff --git a/server/Dockerfile b/server/Dockerfile
new file mode 100644
index 00000000..816ae185
--- /dev/null
+++ b/server/Dockerfile
@@ -0,0 +1,14 @@
+FROM node:18
+RUN mkdir -p /app
+WORKDIR /app
+ADD . /app/
+
+RUN rm yarn.lock || true
+RUN rm package-lock.json || true
+RUN yarn
+RUN yarn build
+
+ENV HOST 0.0.0.0
+EXPOSE 3000
+
+CMD [ "yarn", "start"]
\ No newline at end of file
diff --git a/server/README.md b/server/README.md
new file mode 100644
index 00000000..83729419
--- /dev/null
+++ b/server/README.md
@@ -0,0 +1,73 @@
+
+
+
+
+[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
+[circleci-url]: https://circleci.com/gh/nestjs/nest
+
+ A progressive Node.js framework for building efficient and scalable server-side applications.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Description
+
+[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
+
+## Installation
+
+```bash
+$ yarn install
+```
+
+## Running the app
+
+```bash
+# development
+$ yarn run start
+
+# watch mode
+$ yarn run start:dev
+
+# production mode
+$ yarn run start:prod
+```
+
+## Test
+
+```bash
+# unit tests
+$ yarn run test
+
+# e2e tests
+$ yarn run test:e2e
+
+# test coverage
+$ yarn run test:cov
+```
+
+## Support
+
+Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
+
+## Stay in touch
+
+- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
+- Website - [https://nestjs.com](https://nestjs.com/)
+- Twitter - [@nestframework](https://twitter.com/nestframework)
+
+## License
+
+Nest is [MIT licensed](LICENSE).
diff --git a/server/docker-compose.yaml b/server/docker-compose.yaml
new file mode 100644
index 00000000..cb46eb51
--- /dev/null
+++ b/server/docker-compose.yaml
@@ -0,0 +1,35 @@
+version: '3.8'
+services:
+ postgresql_db:
+ image: postgres:15
+ restart: always
+ volumes:
+ - ./postgres-data:/var/lib/postgresql/data
+ ports:
+ - '5433:5432'
+ environment:
+ POSTGRES_USER: ${DB_USERNAME}
+ POSTGRES_PASSWORD: ${DB_PASSWORD}
+ POSTGRES_DB: ${DB_DATABASE}
+ redis:
+ image: redis
+ restart: always
+ ports:
+ - 6379:6379
+
+ # nestjs_server:
+ # build: .
+ # ports:
+ # - '3000:3000'
+ # depends_on:
+ # - postgresql_db
+ # environment:
+ # JWT_SECRET: ${JWT_SECRET}
+ # HASH_ROUNDS: ${HASH_ROUNDS}
+ # PROTOCOL: ${PROTOCOL}
+ # HOST: ${HOST}
+ # DB_HOST: ${DB_HOST}
+ # DB_PORT: ${DB_PORT}
+ # DB_USERNAME: ${DB_USERNAME}
+ # DB_PASSWORD: ${DB_PASSWORD}
+ # DB_DATABASE: ${DB_DATABASE}
diff --git a/server/nest-cli.json b/server/nest-cli.json
new file mode 100644
index 00000000..f9aa683b
--- /dev/null
+++ b/server/nest-cli.json
@@ -0,0 +1,8 @@
+{
+ "$schema": "https://json.schemastore.org/nest-cli",
+ "collection": "@nestjs/schematics",
+ "sourceRoot": "src",
+ "compilerOptions": {
+ "deleteOutDir": true
+ }
+}
diff --git a/server/package.json b/server/package.json
new file mode 100644
index 00000000..e6a5fa33
--- /dev/null
+++ b/server/package.json
@@ -0,0 +1,92 @@
+{
+ "name": "server",
+ "version": "0.0.1",
+ "description": "",
+ "author": "",
+ "private": true,
+ "license": "UNLICENSED",
+ "scripts": {
+ "build": "nest build",
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
+ "start": "nest start",
+ "start:dev": "nest start --watch",
+ "start:debug": "nest start --debug --watch",
+ "start:prod": "node dist/main",
+ "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
+ "test": "jest",
+ "test:watch": "jest --watch",
+ "test:cov": "jest --coverage",
+ "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
+ "test:e2e": "jest --config ./test/jest-e2e.json"
+ },
+ "dependencies": {
+ "@nestjs/axios": "^3.0.1",
+ "@nestjs/common": "^10.0.0",
+ "@nestjs/config": "^3.1.1",
+ "@nestjs/core": "^10.0.0",
+ "@nestjs/jwt": "^10.2.0",
+ "@nestjs/mapped-types": "*",
+ "@nestjs/platform-express": "^10.0.0",
+ "@nestjs/platform-ws": "^10.2.10",
+ "@nestjs/typeorm": "^10.0.0",
+ "@nestjs/websockets": "^10.2.10",
+ "@panva/jose": "^1.9.3",
+ "axios": "^1.6.2",
+ "class-transformer": "^0.5.1",
+ "class-validator": "^0.14.0",
+ "cookie-parser": "^1.4.6",
+ "nest-winston": "^1.9.4",
+ "pg": "^8.11.3",
+ "redis": "^4.6.11",
+ "reflect-metadata": "^0.1.13",
+ "rxjs": "^7.8.1",
+ "typeorm": "^0.3.17",
+ "uuid": "^9.0.1",
+ "winston": "^3.11.0",
+ "winston-daily-rotate-file": "^4.7.1"
+ },
+ "devDependencies": {
+ "@nestjs/cli": "^10.0.0",
+ "@nestjs/schematics": "^10.0.0",
+ "@nestjs/testing": "^10.0.0",
+ "@types/express": "^4.17.17",
+ "@types/jest": "^29.5.2",
+ "@types/node": "^20.3.1",
+ "@types/supertest": "^2.0.12",
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
+ "@typescript-eslint/parser": "^6.0.0",
+ "eslint": "^8.42.0",
+ "eslint-config-prettier": "^9.0.0",
+ "eslint-plugin-prettier": "^5.0.0",
+ "jest": "^29.5.0",
+ "prettier": "^3.0.0",
+ "source-map-support": "^0.5.21",
+ "supertest": "^6.3.3",
+ "ts-jest": "^29.1.0",
+ "ts-loader": "^9.4.3",
+ "ts-node": "^10.9.1",
+ "tsconfig-paths": "^4.2.0",
+ "typescript": "^5.1.3"
+ },
+ "jest": {
+ "moduleFileExtensions": [
+ "js",
+ "json",
+ "ts"
+ ],
+ "rootDir": "src",
+ "moduleNameMapper": {
+ "^src/(.*)$": "/$1",
+ "^test/(.*)$": "/../test/$1"
+ },
+ "testRegex": ".*\\.spec\\.ts$",
+ "transform": {
+ "^.+\\.(t|j)s$": "ts-jest"
+ },
+ "collectCoverageFrom": [
+ "**/*.(t|j)s"
+ ],
+ "coverageDirectory": "../coverage",
+ "testEnvironment": "node"
+ }
+}
diff --git a/server/redis/redis.module.ts b/server/redis/redis.module.ts
new file mode 100644
index 00000000..cd8e2baa
--- /dev/null
+++ b/server/redis/redis.module.ts
@@ -0,0 +1,82 @@
+import { DynamicModule, Global, Module } from '@nestjs/common';
+import { RedisClientType, createClient } from 'redis';
+import { RedisService } from './redis.service';
+
+/**
+ * RedisModule은 NestJS 애플리케이션에서 Redis 클라이언트를 설정하고 관리하는데 사용되는 모듈이다.
+ */
+@Global()
+@Module({})
+export class RedisModule {
+ /**
+ * forRoot 메서드는 Redis 클라이언트를 생성하고 초기화한다. 이 메서드는 DynamicModule을 반환한다.
+ */
+ static forRoot(): DynamicModule {
+ /**
+ * 일반적인 데이터 작업을 위한 Redis 클라이언트를 제공한다.
+ */
+ const redisProvider = {
+ provide: 'REDIS_CLIENT',
+ useFactory: async (): Promise => {
+ const client = createClient({
+ url: process.env.REDIS_URL, // Redis 서버의 URL
+ // username: process.env.REDIS_USERNAME, // Redis 사용자 이름
+ // password: process.env.REDIS_PASSWORD, // Redis 비밀번호
+ }) as RedisClientType;
+ await client.connect(); // 클라이언트 연결
+ return client; // 연결된 클라이언트 반환
+ },
+ };
+
+ /**
+ * 메시지를 Redis 채널에 게시하는 데 사용되는 Redis 클라이언트를 제공한다.
+ */
+ const redisPubProvider = {
+ provide: 'REDIS_PUB_CLIENT',
+ useFactory: async (): Promise => {
+ const client = createClient({
+ url: process.env.REDIS_URL,
+ // username: process.env.REDIS_USERNAME,
+ // password: process.env.REDIS_PASSWORD,
+ }) as RedisClientType;
+ await client.connect();
+ return client;
+ },
+ };
+
+ /**
+ * Redis 채널에서 메시지를 수신하는 데 사용되는 Redis 클라이언트를 제공한다.
+ */
+ const redisSubProvider = {
+ provide: 'REDIS_SUB_CLIENT',
+ useFactory: async (): Promise => {
+ const client = createClient({
+ url: process.env.REDIS_URL,
+ // username: process.env.REDIS_USERNAME,
+ // password: process.env.REDIS_PASSWORD,
+ }) as RedisClientType;
+ await client.connect();
+ return client;
+ },
+ };
+
+ /**
+ * 모듈 구성을 반환한다. 여기에는 Redis 클라이언트 및 해당 클라이언트를 다른 모듈에서 주입하여 사용할 수 있도록 하는 설정이 포함되어 있다.
+ */
+ return {
+ module: RedisModule,
+ providers: [
+ redisProvider,
+ redisPubProvider,
+ redisSubProvider,
+ RedisService,
+ ],
+ exports: [
+ redisProvider,
+ redisPubProvider,
+ redisSubProvider,
+ RedisService,
+ ],
+ };
+ }
+}
diff --git a/server/redis/redis.service.ts b/server/redis/redis.service.ts
new file mode 100644
index 00000000..92e7e602
--- /dev/null
+++ b/server/redis/redis.service.ts
@@ -0,0 +1,21 @@
+import { Inject, Injectable } from '@nestjs/common';
+import { RedisClientType } from 'redis';
+
+@Injectable()
+export class RedisService {
+ constructor(
+ @Inject('REDIS_SUB_CLIENT')
+ private readonly redisSubscriber: RedisClientType,
+ @Inject('REDIS_PUB_CLIENT')
+ private readonly redisPublisher: RedisClientType,
+ ) {}
+
+ subscribeToChannel(channel: string, callback: Function) {
+ this.redisSubscriber.subscribe(channel, (message) => {
+ callback(message);
+ });
+ }
+ publishToChannel(channel: string, message: string) {
+ this.redisPublisher.publish(channel, message);
+ }
+}
diff --git a/server/src/admin/admin.controller.spec.ts b/server/src/admin/admin.controller.spec.ts
new file mode 100644
index 00000000..714d356e
--- /dev/null
+++ b/server/src/admin/admin.controller.spec.ts
@@ -0,0 +1,20 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { AdminController } from './admin.controller';
+import { AdminService } from './admin.service';
+
+describe('AdminController', () => {
+ let controller: AdminController;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ controllers: [AdminController],
+ providers: [AdminService],
+ }).compile();
+
+ controller = module.get(AdminController);
+ });
+
+ it('should be defined', () => {
+ expect(controller).toBeDefined();
+ });
+});
diff --git a/server/src/admin/admin.controller.ts b/server/src/admin/admin.controller.ts
new file mode 100644
index 00000000..68b30d1e
--- /dev/null
+++ b/server/src/admin/admin.controller.ts
@@ -0,0 +1,59 @@
+import {
+ Controller,
+ Get,
+ Req,
+ Res,
+ UnauthorizedException,
+} from '@nestjs/common';
+import { Response } from 'express';
+import { RedisService } from 'redis/redis.service';
+import { UserId } from 'src/users/decorator/userId.decorator';
+import { channels } from './const/channels.const';
+
+@Controller('admin')
+export class AdminController {
+ constructor(private readonly redisService: RedisService) {}
+
+ @Get('events')
+ sse(@Req() req, @Res() res: Response, @UserId() userId: number) {
+ res.setHeader('Content-Type', 'text/event-stream');
+ res.setHeader('Cache-Control', 'no-cache');
+ res.setHeader('Connection', 'keep-alive');
+ res.flushHeaders();
+
+ if (userId !== 1) {
+ throw new UnauthorizedException('관리자가 아닙니다.');
+ }
+
+ const changeFormat = (channel, message) => {
+ const result = { channel, message };
+ return JSON.stringify(result);
+ };
+
+ res.write(`data: ${changeFormat('notice', 'Server connected')}\n\n`);
+ channels.forEach((channel) => {
+ this.redisService.subscribeToChannel(channel, (message) => {
+ res.write(`data: ${changeFormat(channel, message)}\n\n`);
+ });
+ });
+
+ req.on('close', () => {
+ res.end();
+ });
+ }
+ @Get('generate')
+ generate(@UserId() userId: number) {
+ if (userId !== 1) {
+ throw new UnauthorizedException('관리자가 아닙니다.');
+ }
+ this.redisService.publishToChannel('channel', 'processAiResult');
+ }
+
+ @Get('category')
+ category(@UserId() userId: number) {
+ if (userId !== 1) {
+ throw new UnauthorizedException('관리자가 아닙니다.');
+ }
+ this.redisService.publishToChannel('channel', 'processCategory');
+ }
+}
diff --git a/server/src/admin/admin.module.ts b/server/src/admin/admin.module.ts
new file mode 100644
index 00000000..10aa83ba
--- /dev/null
+++ b/server/src/admin/admin.module.ts
@@ -0,0 +1,9 @@
+import { Module } from '@nestjs/common';
+import { AdminController } from './admin.controller';
+import { AdminService } from './admin.service';
+
+@Module({
+ controllers: [AdminController],
+ providers: [AdminService],
+})
+export class AdminModule {}
diff --git a/server/src/admin/admin.service.spec.ts b/server/src/admin/admin.service.spec.ts
new file mode 100644
index 00000000..5e5e153d
--- /dev/null
+++ b/server/src/admin/admin.service.spec.ts
@@ -0,0 +1,18 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { AdminService } from './admin.service';
+
+describe('AdminService', () => {
+ let service: AdminService;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [AdminService],
+ }).compile();
+
+ service = module.get(AdminService);
+ });
+
+ it('should be defined', () => {
+ expect(service).toBeDefined();
+ });
+});
diff --git a/server/src/admin/admin.service.ts b/server/src/admin/admin.service.ts
new file mode 100644
index 00000000..796f9fd1
--- /dev/null
+++ b/server/src/admin/admin.service.ts
@@ -0,0 +1,4 @@
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class AdminService {}
diff --git a/server/src/admin/const/channels.const.ts b/server/src/admin/const/channels.const.ts
new file mode 100644
index 00000000..a4e3ed4a
--- /dev/null
+++ b/server/src/admin/const/channels.const.ts
@@ -0,0 +1,7 @@
+export const channels = [
+ 'channel',
+ 'sharedChecklist',
+ 'ai_result',
+ 'httpLog',
+ 'wsLog',
+];
diff --git a/server/src/admin/html/admin.html b/server/src/admin/html/admin.html
new file mode 100644
index 00000000..491ea157
--- /dev/null
+++ b/server/src/admin/html/admin.html
@@ -0,0 +1,291 @@
+
+
+
+
+ Redis Pub/Sub Messages
+
+
+
+ Received Messages
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/server/src/app.controller.spec.ts b/server/src/app.controller.spec.ts
new file mode 100644
index 00000000..d22f3890
--- /dev/null
+++ b/server/src/app.controller.spec.ts
@@ -0,0 +1,22 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { AppController } from './app.controller';
+import { AppService } from './app.service';
+
+describe('AppController', () => {
+ let appController: AppController;
+
+ beforeEach(async () => {
+ const app: TestingModule = await Test.createTestingModule({
+ controllers: [AppController],
+ providers: [AppService],
+ }).compile();
+
+ appController = app.get(AppController);
+ });
+
+ describe('root', () => {
+ it('should return "Hello World!"', () => {
+ expect(appController.getHello()).toBe('Hello World!');
+ });
+ });
+});
diff --git a/server/src/app.controller.ts b/server/src/app.controller.ts
new file mode 100644
index 00000000..cce879ee
--- /dev/null
+++ b/server/src/app.controller.ts
@@ -0,0 +1,12 @@
+import { Controller, Get } from '@nestjs/common';
+import { AppService } from './app.service';
+
+@Controller()
+export class AppController {
+ constructor(private readonly appService: AppService) {}
+
+ @Get()
+ getHello(): string {
+ return this.appService.getHello();
+ }
+}
diff --git a/server/src/app.module.ts b/server/src/app.module.ts
new file mode 100644
index 00000000..8eb00b14
--- /dev/null
+++ b/server/src/app.module.ts
@@ -0,0 +1,85 @@
+import {
+ MiddlewareConsumer,
+ Module,
+ NestModule,
+ RequestMethod,
+} from '@nestjs/common';
+import { ConfigModule } from '@nestjs/config';
+import { APP_INTERCEPTOR } from '@nestjs/core';
+import { TypeOrmModule } from '@nestjs/typeorm';
+import { WinstonModule } from 'nest-winston';
+import { RedisModule } from 'redis/redis.module';
+import { AdminModule } from './admin/admin.module';
+import { AppController } from './app.controller';
+import { AppService } from './app.service';
+import { AuthModule } from './auth/auth.module';
+import { CategoriesModule } from './categories/categories.module';
+import { ChecklistAiModule } from './checklist-ai/checklist-ai.module';
+import { CommonModule } from './common/common.module';
+import { LoggingInterceptor } from './common/interceptor/log.interceptor';
+import { LoggerMiddleware } from './common/middlewares/logger.middleware';
+import { FeedModel } from './feeds/entity/feed.entity';
+import { FeedsModule } from './feeds/feeds.module';
+import { FolderModel } from './folders/entities/folder.entity';
+import { FoldersModule } from './folders/folders.module';
+import { PrivateChecklistModel } from './folders/private-checklists/entities/private-checklist.entity';
+import { ChecklistsModule } from './folders/private-checklists/private-checklists.module';
+import { SharedChecklistItemModel } from './shared-checklists/entities/shared-checklist-item.entity';
+import { SharedChecklistModel } from './shared-checklists/entities/shared-checklist.entity';
+import { SharedChecklistsModule } from './shared-checklists/shared-checklists.module';
+import { UserModel } from './users/entities/user.entity';
+import { UsersModule } from './users/users.module';
+import { winstonConfig } from './utils/winston.config';
+
+@Module({
+ imports: [
+ ConfigModule.forRoot({
+ envFilePath: '.env',
+ isGlobal: true,
+ }),
+ RedisModule.forRoot(),
+ TypeOrmModule.forRoot({
+ type: 'postgres',
+ host: process.env['DB_HOST'],
+ port: parseInt(process.env['DB_PORT']),
+ username: process.env['DB_USERNAME'],
+ password: process.env['DB_PASSWORD'],
+ database: process.env['DB_DATABASE'],
+ entities: [
+ UserModel,
+ FolderModel,
+ PrivateChecklistModel,
+ SharedChecklistModel,
+ SharedChecklistItemModel,
+ FeedModel,
+ ],
+ synchronize: true, // DO NOT USE IN PRODUCTION
+ }),
+ WinstonModule.forRoot(winstonConfig),
+ CommonModule,
+ UsersModule,
+ FoldersModule,
+ ChecklistsModule,
+ AuthModule,
+ SharedChecklistsModule,
+ ChecklistAiModule,
+ CategoriesModule,
+ FeedsModule,
+ AdminModule,
+ ],
+ controllers: [AppController],
+ providers: [
+ AppService,
+ {
+ provide: APP_INTERCEPTOR,
+ useClass: LoggingInterceptor,
+ },
+ ],
+})
+export class AppModule implements NestModule {
+ configure(consumer: MiddlewareConsumer) {
+ consumer
+ .apply(LoggerMiddleware)
+ .forRoutes({ path: '*', method: RequestMethod.ALL });
+ }
+}
diff --git a/server/src/app.service.ts b/server/src/app.service.ts
new file mode 100644
index 00000000..927d7cca
--- /dev/null
+++ b/server/src/app.service.ts
@@ -0,0 +1,8 @@
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class AppService {
+ getHello(): string {
+ return 'Hello World!';
+ }
+}
diff --git a/server/src/auth/auth.controller.spec.ts b/server/src/auth/auth.controller.spec.ts
new file mode 100644
index 00000000..5ebcc8bb
--- /dev/null
+++ b/server/src/auth/auth.controller.spec.ts
@@ -0,0 +1,24 @@
+import { JwtModule } from '@nestjs/jwt';
+import { Test, TestingModule } from '@nestjs/testing';
+import { UsersModule } from 'src/users/users.module';
+import { TestCommonModule } from 'test/test-common.module';
+import { AuthController } from './auth.controller';
+import { AuthService } from './auth.service';
+
+describe('AuthController', () => {
+ let controller: AuthController;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ imports: [JwtModule.register({}), TestCommonModule, UsersModule],
+ controllers: [AuthController],
+ providers: [AuthService],
+ }).compile();
+
+ controller = module.get(AuthController);
+ });
+
+ it('should be defined', () => {
+ expect(controller).toBeDefined();
+ });
+});
diff --git a/server/src/auth/auth.controller.ts b/server/src/auth/auth.controller.ts
new file mode 100644
index 00000000..bdfaf092
--- /dev/null
+++ b/server/src/auth/auth.controller.ts
@@ -0,0 +1,60 @@
+import { Body, Controller, Headers, Post } from '@nestjs/common';
+import { AuthService } from './auth.service';
+import { AuthUserDto } from './dto/auth-user.dto';
+import { loginUserDto } from './dto/login-user.dto';
+import { registerUserDto } from './dto/register-user.dto';
+
+@Controller('auth')
+export class AuthController {
+ constructor(private readonly authService: AuthService) {}
+
+ /**
+ * Apple 로그인/등록을 처리한다.
+ * @param dto {AuthUserDto}
+ * @returns {accessToken, refreshToken}
+ */
+ @Post('apple/login')
+ async postAppleLogin(
+ @Body() dto: AuthUserDto,
+ ): Promise<{ accessToken: string; refreshToken: string }> {
+ return await this.authService.registerOrLoginWithApple(dto);
+ }
+
+ /**
+ * 이메일과 프로바이더를 통해 로그인한다. (개발자용)
+ * @param user {loginUserDto}
+ * @returns {accessToken,refreshToken}
+ */
+ @Post('login')
+ async postLogin(@Body() user: loginUserDto) {
+ return await this.authService.loginWithEmailAndProvider(user);
+ }
+
+ /**
+ * refresh 토큰을 통해 access 토큰과 refresh 토큰을 재발급한다
+ * @param rawToken
+ * @returns {accessToken, refreshToken}
+ */
+ @Post('token/access')
+ postAccessToken(
+ @Headers('authorization') rawToken: string,
+ ): Promise<{ accessToken: string; refreshToken: string }> {
+ const token = this.authService.extractTokenFromHeader(rawToken);
+ return this.authService.refreshAccessToken(token);
+ }
+
+ /**
+ * 이메일과 프로바이더를 통해 회원가입한다. (개발자용)
+ * @param user {registerUserDto}
+ * @returns {accessToken,refreshToken}
+ */
+ @Post('register')
+ postRegister(@Body() user: registerUserDto) {
+ return this.authService.registerUser(user);
+ }
+
+ @Post('login/admin')
+ postAdminLogin(@Body() user) {
+ return this.authService.loginAdminUser(user);
+ }
+}
diff --git a/server/src/auth/auth.module.ts b/server/src/auth/auth.module.ts
new file mode 100644
index 00000000..7053e5e5
--- /dev/null
+++ b/server/src/auth/auth.module.ts
@@ -0,0 +1,13 @@
+import { Module } from '@nestjs/common';
+import { JwtModule } from '@nestjs/jwt';
+import { UsersModule } from 'src/users/users.module';
+import { AuthController } from './auth.controller';
+import { AuthService } from './auth.service';
+
+@Module({
+ imports: [JwtModule.register({}), UsersModule],
+ exports: [AuthService],
+ controllers: [AuthController],
+ providers: [AuthService],
+})
+export class AuthModule {}
diff --git a/server/src/auth/auth.service.spec.ts b/server/src/auth/auth.service.spec.ts
new file mode 100644
index 00000000..9cd1bf79
--- /dev/null
+++ b/server/src/auth/auth.service.spec.ts
@@ -0,0 +1,273 @@
+import { UnauthorizedException } from '@nestjs/common';
+import { JwtService } from '@nestjs/jwt';
+import { Test, TestingModule } from '@nestjs/testing';
+import { CreateUserDto } from 'src/users/dto/create-user.dto';
+import { ProviderType, UserModel } from 'src/users/entities/user.entity';
+import { UsersService } from 'src/users/users.service';
+import { AuthService } from './auth.service';
+import { loginUserDto } from './dto/login-user.dto';
+
+describe('AuthService', () => {
+ let authService: AuthService;
+ let jwtService: JwtService;
+ let usersService: UsersService;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [
+ AuthService,
+ {
+ provide: JwtService,
+ useValue: {
+ sign: jest.fn(),
+ verify: jest.fn(),
+ },
+ },
+ {
+ provide: UsersService,
+ useValue: {
+ findUserByEmail: jest.fn(),
+ createUser: jest.fn(),
+ },
+ },
+ ],
+ }).compile();
+
+ authService = module.get(AuthService);
+ jwtService = module.get(JwtService);
+ usersService = module.get(UsersService);
+ });
+ describe('signToken', () => {
+ it('유저 정보로 access 토큰을 발급한다.', () => {
+ const user = { email: 'test@example.com', userId: 1 } as UserModel;
+ const token = 'access_token';
+ jest.spyOn(jwtService, 'sign').mockReturnValue(token);
+
+ const result = authService.signToken(user, 'access');
+
+ expect(jwtService.sign).toHaveBeenCalledWith(expect.anything(), {
+ secret: process.env.JWT_SECRET,
+ expiresIn: 300,
+ });
+ expect(result).toEqual(token);
+ });
+
+ it('유저 정보로 refresh 토큰을 발급한다.', () => {
+ const user = { email: 'test@example.com', userId: 1 } as UserModel;
+ const token = 'refresh_token';
+ jest.spyOn(jwtService, 'sign').mockReturnValue(token);
+
+ const result = authService.signToken(user, 'refresh');
+
+ expect(jwtService.sign).toHaveBeenCalledWith(expect.anything(), {
+ secret: process.env.JWT_SECRET,
+ expiresIn: 3600,
+ });
+ expect(result).toEqual(token);
+ });
+ });
+
+ describe('verifyToken', () => {
+ it('유효한 토큰을 검증한다.', () => {
+ const token = 'valid_token';
+ const payload = { email: 'test@example.com', userID: 1 };
+ jest.spyOn(jwtService, 'verify').mockReturnValue(payload);
+
+ const result = authService.verifyToken(token);
+
+ expect(jwtService.verify).toHaveBeenCalledWith(token, expect.anything());
+ expect(result).toEqual(payload);
+ });
+
+ it('유효하지 않은 토큰은 UnauthorizedException을 발생시킨다.', () => {
+ jest.spyOn(jwtService, 'verify').mockImplementation(() => {
+ throw new Error();
+ });
+
+ expect(() => authService.verifyToken('invalid_token')).toThrow(
+ UnauthorizedException,
+ );
+ });
+ });
+
+ describe('refreshAccessToken', () => {
+ it('유효한 refresh 토큰으로 access 토큰을 재발급한다.', async () => {
+ const refreshToken = 'valid_refresh_token';
+ const accessToken = 'new_access_token';
+ const newRefreshToken = 'new_refresh_token';
+
+ jest
+ .spyOn(authService, 'verifyToken')
+ .mockReturnValue({ tokenType: 'refresh' });
+
+ jest
+ .spyOn(authService, 'signToken')
+ .mockReturnValueOnce(accessToken) // 첫 번째 호출에서 accessToken 반환
+ .mockReturnValueOnce(newRefreshToken); // 두 번째 호출에서 newRefreshToken 반환
+
+ const result = await authService.refreshAccessToken(refreshToken);
+
+ expect(authService.verifyToken).toHaveBeenCalledWith(refreshToken);
+ expect(authService.signToken).toHaveBeenCalledWith(
+ expect.anything(),
+ 'access',
+ );
+ expect(authService.signToken).toHaveBeenCalledWith(
+ expect.anything(),
+ 'refresh',
+ );
+ expect(result).toEqual({
+ accessToken: accessToken,
+ refreshToken: newRefreshToken,
+ });
+ });
+
+ it('access 토큰을 재발급하는데 refresh 토큰이 아닌 경우 UnauthorizedException을 발생시킨다.', async () => {
+ const invalidToken = 'invalid_refresh_token';
+ jest
+ .spyOn(authService, 'verifyToken')
+ .mockReturnValue(Promise.resolve({ tokenType: 'access' }));
+
+ await expect(
+ authService.refreshAccessToken(invalidToken),
+ ).rejects.toThrow(UnauthorizedException);
+ });
+ });
+
+ describe('loginUser', () => {
+ it('유저 정보로 access 토큰과 refresh 토큰을 발급한다.', () => {
+ const user = { email: 'test@example.com', userId: 1 } as UserModel;
+ const accessToken = 'access_token';
+ const refreshToken = 'refresh_token';
+ jest
+ .spyOn(authService, 'signToken')
+ .mockImplementation((user, tokenType) =>
+ tokenType === 'access' ? accessToken : refreshToken,
+ );
+
+ const result = authService.loginUser(user);
+
+ expect(authService.signToken).toHaveBeenCalledWith(user, 'access');
+ expect(authService.signToken).toHaveBeenCalledWith(user, 'refresh');
+ expect(result).toEqual({ accessToken, refreshToken });
+ });
+ });
+ describe('authenticateWithEmailAndProvider', () => {
+ it('유효한 이메일과 provider로 유저를 인증한다.', async () => {
+ const user: loginUserDto = {
+ email: 'test@example.com',
+ provider: ProviderType.APPLE,
+ };
+ const existUser = { ...user, userId: 1 } as UserModel;
+ jest.spyOn(usersService, 'findUserByEmail').mockResolvedValue(existUser);
+
+ const result = await authService.authenticateWithEmailAndProvider(user);
+
+ expect(usersService.findUserByEmail).toHaveBeenCalledWith(user.email);
+ expect(result).toEqual(existUser);
+ });
+
+ it('존재하지 않는 이메일이면 UnauthorizedException을 발생시킨다.', async () => {
+ const user: loginUserDto = {
+ email: 'nonexistent@example.com',
+ provider: ProviderType.APPLE,
+ };
+ jest.spyOn(usersService, 'findUserByEmail').mockResolvedValue(null);
+
+ await expect(
+ authService.authenticateWithEmailAndProvider(user),
+ ).rejects.toThrow(UnauthorizedException);
+ });
+
+ it('provider가 다르면 UnauthorizedException을 발생시킨다.', async () => {
+ const user: loginUserDto = {
+ email: 'test@example.com',
+ provider: ProviderType.GOOGLE,
+ };
+ const existUser = { ...user, provider: 'APPLE', userId: 1 } as UserModel;
+ jest.spyOn(usersService, 'findUserByEmail').mockResolvedValue(existUser);
+
+ await expect(
+ authService.authenticateWithEmailAndProvider(user),
+ ).rejects.toThrow(UnauthorizedException);
+ });
+ });
+
+ describe('loginWithEmailAndProvider', () => {
+ it('유효한 이메일과 provider로 로그인하고 토큰을 발급한다.', async () => {
+ const user: loginUserDto = {
+ email: 'test@example.com',
+ provider: ProviderType.APPLE,
+ };
+ const existUser = {
+ email: user.email,
+ userId: 1,
+ nickname: 'test',
+ } as UserModel;
+ jest
+ .spyOn(authService, 'authenticateWithEmailAndProvider')
+ .mockResolvedValue(existUser);
+ jest.spyOn(authService, 'loginUser').mockReturnValue({
+ accessToken: 'access_token',
+ refreshToken: 'refresh_token',
+ nickname: 'test',
+ });
+
+ const result = await authService.loginWithEmailAndProvider(user);
+
+ expect(authService.authenticateWithEmailAndProvider).toHaveBeenCalledWith(
+ user,
+ );
+ expect(authService.loginUser).toHaveBeenCalledWith(existUser);
+ expect(result).toEqual({
+ accessToken: 'access_token',
+ refreshToken: 'refresh_token',
+ });
+ });
+ });
+
+ describe('extractTokenFromHeader', () => {
+ it('헤더에서 토큰을 추출한다.', () => {
+ const header = 'Bearer valid_token';
+
+ const result = authService.extractTokenFromHeader(header);
+
+ expect(result).toEqual('valid_token');
+ });
+
+ it('헤더 형식이 잘못되었을 때 UnauthorizedException을 발생시킨다.', () => {
+ const header = 'invalid_header';
+
+ expect(() => {
+ authService.extractTokenFromHeader(header);
+ }).toThrow(UnauthorizedException);
+ });
+ });
+
+ describe('registerUser', () => {
+ it('유저를 등록하고 토큰을 발급한다.', async () => {
+ const user: CreateUserDto = {
+ email: 'newuser@example.com',
+ provider: ProviderType.APPLE,
+ fullName: 'NewUser',
+ providerId: '1234567890',
+ };
+ const newUser = { ...user, userId: 3 } as UserModel;
+ jest.spyOn(usersService, 'createUser').mockResolvedValue(newUser);
+ jest.spyOn(authService, 'loginUser').mockReturnValue({
+ accessToken: 'access_token',
+ refreshToken: 'refresh_token',
+ nickname: 'NewUser',
+ });
+
+ const result = await authService.registerUser(user);
+
+ expect(usersService.createUser).toHaveBeenCalledWith(user);
+ expect(authService.loginUser).toHaveBeenCalledWith(newUser);
+ expect(result).toEqual({
+ accessToken: 'access_token',
+ refreshToken: 'refresh_token',
+ });
+ });
+ });
+});
diff --git a/server/src/auth/auth.service.ts b/server/src/auth/auth.service.ts
new file mode 100644
index 00000000..2fa8b7ac
--- /dev/null
+++ b/server/src/auth/auth.service.ts
@@ -0,0 +1,278 @@
+import { Injectable, UnauthorizedException } from '@nestjs/common';
+import { JwtService } from '@nestjs/jwt';
+import { JWK } from '@panva/jose';
+import axios from 'axios';
+import { createPublicKey } from 'crypto';
+import * as jwt from 'jsonwebtoken';
+import { CreateUserDto } from 'src/users/dto/create-user.dto';
+import { ProviderType, UserModel } from 'src/users/entities/user.entity';
+import { UsersService } from 'src/users/users.service';
+import { AuthUserDto } from './dto/auth-user.dto';
+import { loginUserDto } from './dto/login-user.dto';
+
+type TokenType = 'access' | 'refresh';
+
+@Injectable()
+export class AuthService {
+ constructor(
+ private readonly usersService: UsersService,
+ private readonly jwtService: JwtService,
+ ) {}
+
+ /**
+ * Apple ID 토큰을 검증합니다.
+ * @param idToken Apple ID 토큰
+ // * @param expectedNonce 클라이언트에서 전달된 nonce 값
+ * @returns {Promise}
+ */
+ async verifyAppleIdToken(idToken: string): Promise {
+ const decodedTokenHeader = jwt.decode(idToken, { complete: true }).header;
+
+ // Apple 공개키 가져오기
+ const applePublicKey = await this.getApplePublicKey(decodedTokenHeader.kid);
+
+ // Apple ID 토큰 검증
+ const decodedIdToken = jwt.verify(idToken, applePublicKey, {
+ algorithms: ['RS256'],
+ }) as jwt.JwtPayload;
+
+ if (!decodedIdToken) {
+ throw new UnauthorizedException('ID 토큰 디코드 오류');
+ }
+
+ // 'iss' 필드 검증
+ if (decodedIdToken.iss !== 'https://appleid.apple.com') {
+ throw new UnauthorizedException('잘못된 issuer');
+ }
+
+ // 'aud' 필드 검증
+ if (decodedIdToken.aud !== process.env['SUB']) {
+ throw new UnauthorizedException('잘못된 audience');
+ }
+
+ // // nonce 검증
+ // if (decodedIdToken.nonce !== expectedNonce) {
+ // throw new UnauthorizedException('Nonce 값이 일치하지 않습니다.');
+ // }
+
+ return decodedIdToken;
+ }
+
+ /**
+ * Apple 공개 키를 가져옵니다.
+ * @param {string} kid
+ * @returns {Promise}
+ */
+ async getApplePublicKey(kid: string) {
+ try {
+ // Apple 의 공개 키를 JWK 형식으로 가져오기
+ const response = await axios.get('https://appleid.apple.com/auth/keys');
+
+ // 일치하는 kid 를 가진 키를 찾기
+ const keys = response.data.keys;
+ const matchingKey = keys.find((key) => key.kid === kid);
+
+ if (!matchingKey) {
+ throw new Error('Matching key not found.');
+ }
+
+ //@panva/jose 라이브러리의 JWK.asKey 메소드를 사용하여 JWK 객체를 생성하기
+ const jwk = JWK.asKey(matchingKey);
+
+ // Node.js의 crypto 모듈의 createPublicKey 함수를 사용하여 JWK를 PEM 형식으로 변환하기
+ const pem = createPublicKey(jwk.toPEM()).export({
+ type: 'pkcs1',
+ format: 'pem',
+ });
+
+ return pem;
+ } catch (error) {
+ console.error('Apple public key 가져오기 실패:', error);
+ throw new UnauthorizedException(
+ 'Apple public key를 가져오는데 실패했습니다.',
+ );
+ }
+ }
+
+ /**
+ * Apple 로그인/등록을 한번에 처리한다.
+ * @param {AuthUserDto} authUserDto
+ * @returns {Promise<{accessToken: string, refreshToken: string}>}
+ */
+ async registerOrLoginWithApple(
+ authUserDto: AuthUserDto,
+ ): Promise<{ accessToken: string; refreshToken: string }> {
+ const { identityToken, fullName } = authUserDto;
+
+ // Apple ID 토큰 검증
+ const decodedIdToken = await this.verifyAppleIdToken(identityToken);
+
+ let user = await this.usersService.findUserByAppleId(decodedIdToken.sub);
+
+ if (!user) {
+ // 사용자가 존재하지 않으면 새로 생성
+ user = await this.usersService.createAppleUser({
+ providerId: decodedIdToken.sub,
+ provider: ProviderType.APPLE,
+ email: decodedIdToken.email, // 이메일은 decodedIdToken에서 추출
+ fullName: fullName || '',
+ nickname: fullName || '',
+ });
+ }
+
+ // 사용자에 대한 서비스의 JWT 토큰 생성
+ return this.loginUser(user);
+ }
+
+ /**
+ * 유저 정보를 통해 signToken()을 호출하여 access/refresh 토큰을 반환한다.
+ * @param {UserModel} user
+ * @returns {{accessToken: string, refreshToken: string}}
+ */
+
+ loginUser(user: UserModel): {
+ accessToken: string;
+ refreshToken: string;
+ nickname: string;
+ } {
+ const accessToken = this.signToken(user, 'access');
+ const refreshToken = this.signToken(user, 'refresh');
+
+ return { accessToken, refreshToken, nickname: user.nickname };
+ }
+
+ /**
+ * 유저 정보를 통해 access/refresh 토큰을 발급한다.
+ * @param user 유저 정보
+ * @param tokenType 토큰 타입 (access/refresh)
+ * @returns 토큰
+ */
+ signToken(user: UserModel, tokenType: TokenType) {
+ const payload = {
+ email: user.email,
+ userId: user.userId,
+ tokenType,
+ };
+ const ONE_WEEK = 7 * 24 * 60 * 60;
+ return this.jwtService.sign(payload, {
+ secret: process.env['JWT_SECRET'],
+ // expiresIn: tokenType === 'access' ? 300 : 3600,
+ expiresIn: tokenType === 'access' ? ONE_WEEK : ONE_WEEK,
+ });
+ }
+
+ /**
+ * 토근을 검증한다. 검증에 실패하면 UnauthorizedException 을 발생시킨다.
+ * @param token
+ * @returns payload
+ */
+ verifyToken(token: string) {
+ try {
+ return this.jwtService.verify(token, {
+ secret: process.env['JWT_SECRET'],
+ });
+ } catch (error) {
+ throw new UnauthorizedException('토큰이 만료되었거나 잘못된 토큰입니다.');
+ }
+ }
+
+ /**
+ * refresh 토큰을 통해 access 토큰과 refresh 토큰을 재발급한다.
+ * @param refreshToken
+ * @returns { accessToken: string, refreshToken: string}
+ */
+ async refreshAccessToken(refreshToken: string) {
+ const payload = await this.verifyToken(refreshToken);
+
+ if (payload.tokenType !== 'refresh') {
+ throw new UnauthorizedException(
+ 'access토큰 재발급은 refresh 토큰으로만 가능합니다.',
+ );
+ }
+ const newAccessToken = this.signToken({ ...payload }, 'access');
+ const newRefreshToken = this.signToken({ ...payload }, 'refresh');
+
+ return { accessToken: newAccessToken, refreshToken: newRefreshToken };
+ }
+
+ /**
+ * 이메일과 provider 를 통해 유저를 인증한다.
+ * 없는 이메일이면 UnauthorizedException 을 발생시킨다.
+ * provider 가 다르면 UnauthorizedException 을 발생시키고 어떤 provider 로 가입되어 있는지 알려준다.
+ * @param user
+ * @returns existUser
+ */
+ async authenticateWithEmailAndProvider(user: loginUserDto) {
+ const existUser = await this.usersService.findUserByEmail(user.email);
+ if (!existUser) {
+ throw new UnauthorizedException('존재하지 않는 유저입니다.');
+ }
+ if (existUser.provider !== user.provider) {
+ throw new UnauthorizedException(
+ `해당 이메일은 ${existUser.provider}로 가입된 유저입니다.`,
+ );
+ }
+ return existUser;
+ }
+
+ /**
+ * 이메일과 provider 를 통해 유저를 인증하고 토큰을 발급한다.
+ * @param user
+ * @returns { accessToken: string, refreshToken: string}
+ */
+ async loginWithEmailAndProvider(
+ user: loginUserDto,
+ ): Promise<{ accessToken: string; refreshToken: string }> {
+ const existUser = await this.authenticateWithEmailAndProvider(user);
+ return this.loginUser(existUser);
+ }
+
+ /**
+ * 헤더에서 토큰을 추출한다.
+ * @param header
+ * @returns token
+ */
+ extractTokenFromHeader(header: string) {
+ // 정규식을 사용하여 'Bearer' 토큰 추출
+ const bearerRegex = /^Bearer (.+)$/i;
+ const match = header.match(bearerRegex);
+ if (!match) {
+ throw new UnauthorizedException('토큰이 올바르지 않습니다.');
+ }
+ // 매치된 그룹 중 첫 번째(토큰 부분)를 반환
+ return match[1];
+ }
+
+ /**
+ * 이메일과 provider 를 통해 유저를 등록하고 토큰을 발급한다.
+ * @param user
+ * @returns { accessToken: string, refreshToken: string}
+ */
+ async registerUser(
+ user: CreateUserDto,
+ ): Promise<{ accessToken: string; refreshToken: string }> {
+ const newUser = await this.usersService.createUser(user);
+ return this.loginUser(newUser);
+ }
+
+ loginAdminUser(user: any) {
+ const { email, password } = user;
+ console.log(email, password);
+ if (
+ email == process.env.ADMIN_EMAIL &&
+ password == process.env.ADMIN_PASSWORD
+ ) {
+ const accessToken = this.signToken(
+ { email, userId: 1 } as UserModel,
+ 'access',
+ );
+ const refreshToken = this.signToken(
+ { email, userId: 1 } as UserModel,
+ 'access',
+ );
+
+ return { accessToken, refreshToken };
+ }
+ throw new UnauthorizedException('관리자가 아닙니다.');
+ }
+}
diff --git a/server/src/auth/dto/auth-user.dto.ts b/server/src/auth/dto/auth-user.dto.ts
new file mode 100644
index 00000000..487dafa3
--- /dev/null
+++ b/server/src/auth/dto/auth-user.dto.ts
@@ -0,0 +1,11 @@
+import { IsString, IsNotEmpty, IsOptional } from 'class-validator';
+
+export class AuthUserDto {
+ @IsString()
+ @IsNotEmpty()
+ identityToken: string;
+
+ @IsOptional()
+ @IsString()
+ fullName?: string;
+}
diff --git a/server/src/auth/dto/login-user.dto.ts b/server/src/auth/dto/login-user.dto.ts
new file mode 100644
index 00000000..b0dfc8f8
--- /dev/null
+++ b/server/src/auth/dto/login-user.dto.ts
@@ -0,0 +1,7 @@
+import { PickType } from '@nestjs/mapped-types';
+import { registerUserDto } from './register-user.dto';
+
+export class loginUserDto extends PickType(registerUserDto, [
+ 'email',
+ 'provider',
+]) {}
diff --git a/server/src/auth/dto/register-user.dto.ts b/server/src/auth/dto/register-user.dto.ts
new file mode 100644
index 00000000..6861dc9a
--- /dev/null
+++ b/server/src/auth/dto/register-user.dto.ts
@@ -0,0 +1,20 @@
+import { IsNotEmpty, IsString } from 'class-validator';
+import { ProviderType } from 'src/users/entities/user.entity';
+
+export class registerUserDto {
+ @IsString()
+ @IsNotEmpty()
+ email: string;
+
+ @IsString()
+ @IsNotEmpty()
+ provider: ProviderType;
+
+ @IsString()
+ @IsNotEmpty()
+ fullName: string;
+
+ @IsString()
+ @IsNotEmpty()
+ providerId: string;
+}
diff --git a/server/src/auth/entities/auth.entity.ts b/server/src/auth/entities/auth.entity.ts
new file mode 100644
index 00000000..15f15a8b
--- /dev/null
+++ b/server/src/auth/entities/auth.entity.ts
@@ -0,0 +1 @@
+export class Auth {}
diff --git a/server/src/auth/guard/access-token.guard.ts b/server/src/auth/guard/access-token.guard.ts
new file mode 100644
index 00000000..2c563d03
--- /dev/null
+++ b/server/src/auth/guard/access-token.guard.ts
@@ -0,0 +1,63 @@
+import {
+ CanActivate,
+ ExecutionContext,
+ Injectable,
+ UnauthorizedException,
+} from '@nestjs/common';
+import { AuthService } from '../auth.service';
+
+/**
+ * 엑세스 토큰을 검증하는 Guard
+ * 엑세스 토큰이 없거나, 잘못된 경우 오류를 발생시킴
+ * 엑세스 토큰이 유효한 경우 요청 객체에 userId 필드를 추가함
+ */
+@Injectable()
+export class AccessTokenGuard implements CanActivate {
+ constructor(private readonly authService: AuthService) {}
+ async canActivate(context: ExecutionContext): Promise {
+ const req = context.switchToHttp().getRequest();
+ const url = req.url;
+
+ // /auth 경로에 대한 요청은 Guard를 적용하지 않음
+ if (url.startsWith('/auth')) {
+ return true;
+ }
+
+ // /admin 경로에 대한 요청은 Guard를 적용하지 않음 (배포시 제거해야함)
+ // if (url.startsWith('/admin')) {
+ // return true;
+ // }
+
+ let token;
+ // 헤더 또는 쿠키에서 토큰 추출
+ if (req.headers.authorization) {
+ token = this.authService.extractTokenFromHeader(
+ req.headers.authorization,
+ );
+ } else if (req.cookies && req.cookies['accessToken']) {
+ // 쿠키에서 엑세스 토큰을 가져옴
+ token = req.cookies['accessToken'];
+ }
+
+ // 토큰이 없는 경우 예외 발생
+ if (!token) {
+ throw new UnauthorizedException('토큰이 없습니다.');
+ }
+ const result = await this.authService.verifyToken(token);
+
+ // 토큰이 refresh 토큰인 경우 오류 발생
+ if (result.tokenType === 'refresh') {
+ throw new UnauthorizedException('엑세스 토큰이 아닙니다.');
+ }
+
+ // 사용자 ID 추출 및 검증
+ const userId = result?.userId;
+ if (!userId) {
+ throw new UnauthorizedException('엑세스 토큰이 잘못되었습니다.');
+ }
+ // 요청 객체에 userId 추가
+ req.userId = userId;
+
+ return true;
+ }
+}
diff --git a/server/src/categories/categories.controller.spec.ts b/server/src/categories/categories.controller.spec.ts
new file mode 100644
index 00000000..66257dec
--- /dev/null
+++ b/server/src/categories/categories.controller.spec.ts
@@ -0,0 +1,20 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { CategoriesController } from './categories.controller';
+import { CategoriesService } from './categories.service';
+
+describe('CategoriesController', () => {
+ let controller: CategoriesController;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ controllers: [CategoriesController],
+ providers: [CategoriesService],
+ }).compile();
+
+ controller = module.get(CategoriesController);
+ });
+
+ it('should be defined', () => {
+ expect(controller).toBeDefined();
+ });
+});
diff --git a/server/src/categories/categories.controller.ts b/server/src/categories/categories.controller.ts
new file mode 100644
index 00000000..93e7d626
--- /dev/null
+++ b/server/src/categories/categories.controller.ts
@@ -0,0 +1,25 @@
+import { Controller, Get, Param } from '@nestjs/common';
+import { CategoriesService } from './categories.service';
+
+@Controller('categories')
+export class CategoriesController {
+ constructor(private readonly categoriesService: CategoriesService) {}
+
+ @Get('main-categories')
+ getMainCategories() {
+ return this.categoriesService.findMainCategories();
+ }
+
+ @Get(':mainId/sub-categories')
+ getSubCategories(@Param('mainId') mainId: number) {
+ return this.categoriesService.findSubCategories(mainId);
+ }
+
+ @Get(':mainId/sub-categories/:subId/minor-categories')
+ getMinorCategories(
+ @Param('mainId') mainId: number,
+ @Param('subId') subId: number,
+ ) {
+ return this.categoriesService.findMinorCategories(mainId, subId);
+ }
+}
diff --git a/server/src/categories/categories.module.ts b/server/src/categories/categories.module.ts
new file mode 100644
index 00000000..3499b76a
--- /dev/null
+++ b/server/src/categories/categories.module.ts
@@ -0,0 +1,9 @@
+import { Module } from '@nestjs/common';
+import { CategoriesService } from './categories.service';
+import { CategoriesController } from './categories.controller';
+
+@Module({
+ controllers: [CategoriesController],
+ providers: [CategoriesService],
+})
+export class CategoriesModule {}
diff --git a/server/src/categories/categories.service.spec.ts b/server/src/categories/categories.service.spec.ts
new file mode 100644
index 00000000..56407d1f
--- /dev/null
+++ b/server/src/categories/categories.service.spec.ts
@@ -0,0 +1,69 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { CategoriesService } from './categories.service';
+import { CATEGORIES } from './const/categories.const';
+import { BadRequestException } from '@nestjs/common';
+
+describe('CategoriesService', () => {
+ let service: CategoriesService;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [CategoriesService],
+ }).compile();
+
+ service = module.get(CategoriesService);
+ });
+
+ it('findMainCategories() : 모든 대카테고리를 반환한다', () => {
+ const result = service.findMainCategories();
+ expect(result).toEqual(
+ CATEGORIES.mainCategory.map(({ id, name }) => ({ id, name })),
+ );
+ });
+
+ describe('findSubCategories(mainId)', () => {
+ it('존재하는 대카테고리 ID에 대해 중카테고리를 반환한다', () => {
+ const mainId = 1; // 존재한다고 가정한 대카테고리 ID
+ const result = service.findSubCategories(mainId);
+ const expectedSubCategories = CATEGORIES.mainCategory
+ .find((cat) => cat.id === mainId)
+ ?.subcategories.map(({ id, name }) => ({ id, name }));
+ expect(result).toEqual(expectedSubCategories);
+ });
+
+ it('존재하지 않는 대카테고리 ID에 대해 BadRequestException을 던진다', () => {
+ const mainId = 999; // 존재하지 않는다고 가정한 대카테고리 ID
+ expect(() => service.findSubCategories(mainId)).toThrow(
+ BadRequestException,
+ );
+ });
+ });
+
+ describe('findMinorCategories(mainId, subId)', () => {
+ it('존재하는 중카테고리 ID에 대해 소카테고리를 반환한다', () => {
+ const mainId = 1; // 존재한다고 가정한 대카테고리 ID
+ const subId = 101; // 존재한다고 가정한 중카테고리 ID
+ const result = service.findMinorCategories(mainId, subId);
+ const expectedMinorCategories = CATEGORIES.mainCategory
+ .find((cat) => cat.id === mainId)
+ ?.subcategories.find((sub) => sub.id === subId)?.minorCategories;
+ expect(result).toEqual(expectedMinorCategories);
+ });
+
+ it('존재하지 않는 대카테고리 ID에 대해 BadRequestException을 던진다', () => {
+ const mainId = 999; // 존재하지 않는다고 가정한 대카테고리 ID
+ const subId = 1; // 중카테고리 ID
+ expect(() => service.findMinorCategories(mainId, subId)).toThrow(
+ BadRequestException,
+ );
+ });
+
+ it('존재하지 않는 중카테고리 ID에 대해 BadRequestException을 던진다', () => {
+ const mainId = 1; // 대카테고리 ID
+ const subId = 999; // 존재하지 않는다고 가정한 중카테고리 ID
+ expect(() => service.findMinorCategories(mainId, subId)).toThrow(
+ BadRequestException,
+ );
+ });
+ });
+});
diff --git a/server/src/categories/categories.service.ts b/server/src/categories/categories.service.ts
new file mode 100644
index 00000000..d20953c3
--- /dev/null
+++ b/server/src/categories/categories.service.ts
@@ -0,0 +1,60 @@
+import { BadRequestException, Injectable } from '@nestjs/common';
+import { CATEGORIES } from './const/categories.const';
+
+@Injectable()
+export class CategoriesService {
+ /**
+ * 모든 대카테고리 반환
+ * @returns {{id: number, name: string}[]}
+ */
+ findMainCategories(): { id: number; name: string }[] {
+ return CATEGORIES.mainCategory.map(({ id, name }) => ({ id, name }));
+ }
+
+ /**
+ * 특정 대카테고리의 중카테고리 반환
+ * @param {number} mainId
+ * @returns {{id: number, name: string}[]}
+ */
+ findSubCategories(mainId: number): { id: number; name: string }[] {
+ // 특정 대카테고리의 중카테고리만 반환
+ const mainCategory = CATEGORIES.mainCategory.find(
+ (category) => category.id === (mainId as unknown as number),
+ );
+ if (!mainCategory) {
+ throw new BadRequestException(
+ `대 카테고리 ID ${mainId}은/는 존재하지 않습니다.`,
+ );
+ }
+ return mainCategory.subcategories.map(({ id, name }) => ({ id, name }));
+ }
+
+ /**
+ * 특정 중카테고리의 소카테고리 반환
+ * @param {number} mainId
+ * @param {number} subId
+ * @returns {{id: number; name: string}[]}
+ */
+ findMinorCategories(
+ mainId: number,
+ subId: number,
+ ): { id: number; name: string }[] {
+ const mainCategory = CATEGORIES.mainCategory.find(
+ (category) => category.id === (mainId as unknown as number),
+ );
+ if (!mainCategory) {
+ throw new BadRequestException(
+ `대 카테고리 ID ${mainId}은/는 존재하지 않습니다.`,
+ );
+ }
+ const subCategory = mainCategory.subcategories.find(
+ (sub) => sub.id === (subId as unknown as number),
+ );
+ if (!subCategory) {
+ throw new BadRequestException(
+ `중 카테고리 ID ${subId}은/는 존재하지 않습니다.`,
+ );
+ }
+ return subCategory.minorCategories;
+ }
+}
diff --git a/server/src/categories/const/categories.const.ts b/server/src/categories/const/categories.const.ts
new file mode 100644
index 00000000..7cb88c2f
--- /dev/null
+++ b/server/src/categories/const/categories.const.ts
@@ -0,0 +1,232 @@
+export const CATEGORIES = {
+ mainCategory: [
+ {
+ id: 1,
+ name: '준비물',
+ subcategories: [
+ {
+ id: 101,
+ name: '국내여행',
+ minorCategories: [
+ { id: 10101, name: '부산' },
+ { id: 10102, name: '제주' },
+ { id: 10103, name: '경주' },
+ { id: 10104, name: '강원도' },
+ { id: 10105, name: '전주' },
+ { id: 10106, name: '서울' },
+ { id: 10107, name: '대구' },
+ ],
+ },
+ {
+ id: 102,
+ name: '해외여행',
+ minorCategories: [
+ { id: 10201, name: '라오스' },
+ { id: 10202, name: '태국' },
+ { id: 10203, name: '일본' },
+ { id: 10204, name: '중국' },
+ { id: 10205, name: '미국' },
+ { id: 10206, name: '캐나다' },
+ { id: 10207, name: '영국' },
+ { id: 10208, name: '프랑스' },
+ { id: 10209, name: '스페인' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 2,
+ name: '장소',
+ subcategories: [
+ {
+ id: 201,
+ name: '연인 데이트',
+ minorCategories: [
+ { id: 20101, name: '영화관' },
+ { id: 20102, name: '공원' },
+ { id: 20103, name: '미술관' },
+ { id: 20104, name: '카페' },
+ { id: 20105, name: '바다' },
+ { id: 20106, name: '당일치기' },
+ { id: 20107, name: '캠핑' },
+ { id: 20108, name: '글램핑' },
+ { id: 20109, name: '호텔' },
+ ],
+ },
+ {
+ id: 202,
+ name: '가족 나들이',
+ minorCategories: [
+ { id: 20201, name: '동물원' },
+ { id: 20202, name: '테마파크' },
+ { id: 20203, name: '해변' },
+ { id: 20204, name: '산' },
+ { id: 20205, name: '박물관' },
+ { id: 20206, name: '수족관' },
+ { id: 20207, name: '놀이동산' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 3,
+ name: '활동',
+ subcategories: [
+ {
+ id: 301,
+ name: '자기계발',
+ minorCategories: [
+ { id: 30101, name: '언어 학습' },
+ { id: 30102, name: '프로그래밍' },
+ { id: 30103, name: '취미 개발' },
+ ],
+ },
+ {
+ id: 302,
+ name: '레저 스포츠',
+ minorCategories: [
+ { id: 30201, name: '등산' },
+ { id: 30202, name: '서핑' },
+ { id: 30203, name: '스노우보딩' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 4,
+ name: '식단',
+ subcategories: [
+ {
+ id: 401,
+ name: '다이어트',
+ minorCategories: [
+ { id: 40101, name: '케토' },
+ { id: 40102, name: '저탄수화물' },
+ { id: 40103, name: '지중해식' },
+ ],
+ },
+ {
+ id: 402,
+ name: '건강식',
+ minorCategories: [
+ { id: 40201, name: '채식' },
+ { id: 40202, name: '유기농' },
+ { id: 40203, name: '글루텐 프리' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 5,
+ name: '기술 습득',
+ subcategories: [
+ {
+ id: 501,
+ name: '컴퓨터',
+ minorCategories: [
+ { id: 50101, name: '운영체제' },
+ { id: 50102, name: '데이터베이스 관리' },
+ { id: 50103, name: '네트워크' },
+ { id: 50104, name: '웹 개발' },
+ { id: 50105, name: '앱 개발' },
+ { id: 50106, name: '게임 개발' },
+ { id: 50107, name: '머신러닝' },
+ { id: 50108, name: '인공지능' },
+ { id: 50109, name: '블록체인' },
+ { id: 50110, name: '빅데이터' },
+ { id: 50111, name: '사이버 보안' },
+ { id: 50112, name: 'C언어' },
+ { id: 50113, name: 'C++' },
+ { id: 50114, name: 'C#' },
+ ],
+ },
+ {
+ id: 502,
+ name: '기타 기술',
+ minorCategories: [
+ { id: 50201, name: '그래픽 디자인' },
+ { id: 50202, name: '사진술' },
+ { id: 50203, name: '글쓰기' },
+ { id: 50204, name: '영상 편집' },
+ { id: 50205, name: '음악 제작' },
+ { id: 50206, name: '음악 연주' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 6,
+ name: '건강 관리',
+ subcategories: [
+ {
+ id: 601,
+ name: '정신 건강',
+ minorCategories: [
+ { id: 60101, name: '명상' },
+ { id: 60102, name: '스트레스 관리' },
+ { id: 60103, name: '수면 개선' },
+ ],
+ },
+ {
+ id: 602,
+ name: '신체 건강',
+ minorCategories: [
+ { id: 60201, name: '운동 루틴' },
+ { id: 60202, name: '영양 보충' },
+ { id: 60203, name: '건강 검진' },
+ { id: 60204, name: '피부 관리' },
+ { id: 60205, name: '머리 관리' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 7,
+ name: '취미',
+ subcategories: [
+ {
+ id: 701,
+ name: '음악',
+ minorCategories: [
+ { id: 70101, name: '기타' },
+ { id: 70102, name: '피아노' },
+ { id: 70103, name: '드럼' },
+ { id: 70104, name: '베이스' },
+ { id: 70105, name: '보컬' },
+ { id: 70106, name: '작곡' },
+ { id: 70107, name: '음악 이론' },
+ ],
+ },
+ {
+ id: 702,
+ name: '미술',
+ minorCategories: [
+ { id: 70201, name: '드로잉' },
+ { id: 70202, name: '수채화' },
+ { id: 70203, name: '아크릴화' },
+ { id: 70204, name: '유화' },
+ { id: 70205, name: '파스텔' },
+ { id: 70206, name: '캘리그라피' },
+ { id: 70207, name: '조소' },
+ { id: 70208, name: '판화' },
+ { id: 70209, name: '캐리커쳐' },
+ ],
+ },
+ {
+ id: 703,
+ name: '공예',
+ minorCategories: [
+ { id: 70301, name: '가죽' },
+ { id: 70302, name: '목공' },
+ { id: 70303, name: '도자기' },
+ { id: 70304, name: '비즈' },
+ { id: 70305, name: '플라워' },
+ { id: 70306, name: '캔들' },
+ { id: 70307, name: '향수' },
+ { id: 70308, name: '비누' },
+ ],
+ },
+ ],
+ },
+ ],
+};
diff --git a/server/src/categories/const/valid-ids.const.ts b/server/src/categories/const/valid-ids.const.ts
new file mode 100644
index 00000000..54348534
--- /dev/null
+++ b/server/src/categories/const/valid-ids.const.ts
@@ -0,0 +1,21 @@
+import { CATEGORIES } from './categories.const';
+
+const extractValidIds = (categories) => {
+ const mainCategoryIds = categories.mainCategory.map((cat) => cat.id);
+ const subCategoryIds = categories.mainCategory.flatMap((cat) =>
+ cat.subcategories.map((sub) => sub.id),
+ );
+ const minorCategoryIds = categories.mainCategory.flatMap((cat) =>
+ cat.subcategories.flatMap((sub) =>
+ sub.minorCategories.map((minor) => minor.id),
+ ),
+ );
+
+ return {
+ mainCategoryIds,
+ subCategoryIds,
+ minorCategoryIds,
+ };
+};
+
+export const validIds = extractValidIds(CATEGORIES);
diff --git a/server/src/checklist-ai/checklist-ai.controller.ts b/server/src/checklist-ai/checklist-ai.controller.ts
new file mode 100644
index 00000000..e6363214
--- /dev/null
+++ b/server/src/checklist-ai/checklist-ai.controller.ts
@@ -0,0 +1,13 @@
+import { ChecklistAiService } from './checklist-ai.service';
+import { Body, Controller, Post } from '@nestjs/common';
+import { CreateChecklistItemsDto } from './dto/create-checklist-items.dto';
+
+@Controller('checklist-ai')
+export class ChecklistAiController {
+ constructor(private readonly checklistAiService: ChecklistAiService) {}
+
+ @Post()
+ async getChecklistItemsWithAi(@Body() dto: CreateChecklistItemsDto) {
+ return this.checklistAiService.generateChecklistItemWithAi(dto);
+ }
+}
diff --git a/server/src/checklist-ai/checklist-ai.module.ts b/server/src/checklist-ai/checklist-ai.module.ts
new file mode 100644
index 00000000..0e1680aa
--- /dev/null
+++ b/server/src/checklist-ai/checklist-ai.module.ts
@@ -0,0 +1,11 @@
+import { Module } from '@nestjs/common';
+import { ChecklistAiService } from './checklist-ai.service';
+import { ChecklistAiController } from './checklist-ai.controller';
+import { HttpModule } from '@nestjs/axios';
+
+@Module({
+ imports: [HttpModule],
+ controllers: [ChecklistAiController],
+ providers: [ChecklistAiService],
+})
+export class ChecklistAiModule {}
diff --git a/server/src/checklist-ai/checklist-ai.service.spec.ts b/server/src/checklist-ai/checklist-ai.service.spec.ts
new file mode 100644
index 00000000..6467d1be
--- /dev/null
+++ b/server/src/checklist-ai/checklist-ai.service.spec.ts
@@ -0,0 +1,18 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { ChecklistAiService } from './checklist-ai.service';
+
+describe('ChecklistAiService', () => {
+ let service: ChecklistAiService;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [ChecklistAiService],
+ }).compile();
+
+ service = module.get(ChecklistAiService);
+ });
+
+ it('should be defined', () => {
+ expect(service).toBeDefined();
+ });
+});
diff --git a/server/src/checklist-ai/checklist-ai.service.ts b/server/src/checklist-ai/checklist-ai.service.ts
new file mode 100644
index 00000000..ddc1898d
--- /dev/null
+++ b/server/src/checklist-ai/checklist-ai.service.ts
@@ -0,0 +1,67 @@
+import { HttpService } from '@nestjs/axios';
+import { Injectable, ServiceUnavailableException } from '@nestjs/common';
+import { firstValueFrom } from 'rxjs';
+import * as process from 'process';
+import { CreateChecklistItemsDto } from './dto/create-checklist-items.dto';
+import { AI_OPTIONS } from './const/ai-options.const';
+import { SYSTEM_ROLE } from './const/system-role.const';
+import { CLOVA_API_URL } from './const/request-option.const';
+
+@Injectable()
+export class ChecklistAiService {
+ constructor(private httpService: HttpService) {}
+
+ // HTTP 요청을 보내는 별도의 메서드
+ private async sendRequestToClova(url: string, headers: any, data: any) {
+ return await firstValueFrom(this.httpService.post(url, data, { headers }));
+ }
+
+ // 응답 데이터에서 필요한 정보를 추출하는 별도의 메서드
+ private extractResultData(responseData: any) {
+ // 'result.message.content' 에 직접 접근하여 반환.
+ // 'result' 또는 'message' 가 없는 경우 null 을 반환.
+ return responseData?.result?.message?.content ?? null;
+ }
+
+ private getUserRoleWithDto(dto: CreateChecklistItemsDto) {
+ return {
+ role: 'user',
+ content: `대카테고리: ${dto.mainCategory}, 중카테고리: ${dto.minorCategory}, 소카테고리: ${dto.subCategory}`,
+ };
+ }
+
+ private generateRequestData(dto: CreateChecklistItemsDto) {
+ return {
+ messages: [SYSTEM_ROLE, this.getUserRoleWithDto(dto)],
+ ...AI_OPTIONS,
+ };
+ }
+
+ private generateRequestHeaders() {
+ const CLOVASTUDIO_API_KEY = process.env.X_NCP_CLOVASTUDIO_API_KEY;
+ const APIGW_API_KEY = process.env.X_NCP_APIGW_API_KEY;
+ const REQUEST_ID = process.env.X_NCP_CLOVASTUDIO_REQUEST_ID;
+ return {
+ 'X-NCP-CLOVASTUDIO-API-KEY': CLOVASTUDIO_API_KEY,
+ 'X-NCP-APIGW-API-KEY': APIGW_API_KEY,
+ 'X-NCP-CLOVASTUDIO-REQUEST-ID': REQUEST_ID,
+ 'Content-Type': 'application/json',
+ Accept: 'application/json',
+ };
+ }
+
+ async generateChecklistItemWithAi(dto: CreateChecklistItemsDto) {
+ const url = CLOVA_API_URL;
+ const data = this.generateRequestData(dto);
+ const headers = this.generateRequestHeaders();
+
+ const response = await this.sendRequestToClova(url, headers, data);
+ if (response.status !== 200) {
+ throw new ServiceUnavailableException(
+ 'Chat Completion 서비스 처리 중 오류 발생',
+ );
+ }
+
+ return this.extractResultData(response.data);
+ }
+}
diff --git a/server/src/checklist-ai/const/ai-options.const.ts b/server/src/checklist-ai/const/ai-options.const.ts
new file mode 100644
index 00000000..926d2c6d
--- /dev/null
+++ b/server/src/checklist-ai/const/ai-options.const.ts
@@ -0,0 +1,9 @@
+export const AI_OPTIONS = {
+ topP: 0.8,
+ topK: 0,
+ maxTokens: 256,
+ temperature: 1,
+ repeatPenalty: 7.0,
+ stopBefore: [],
+ includeAiFilters: true,
+};
diff --git a/server/src/checklist-ai/const/request-option.const.ts b/server/src/checklist-ai/const/request-option.const.ts
new file mode 100644
index 00000000..c25c2590
--- /dev/null
+++ b/server/src/checklist-ai/const/request-option.const.ts
@@ -0,0 +1,2 @@
+export const CLOVA_API_URL =
+ 'https://clovastudio.stream.ntruss.com/testapp/v1/chat-completions/HCX-002';
diff --git a/server/src/checklist-ai/const/system-role.const.ts b/server/src/checklist-ai/const/system-role.const.ts
new file mode 100644
index 00000000..04362530
--- /dev/null
+++ b/server/src/checklist-ai/const/system-role.const.ts
@@ -0,0 +1,20 @@
+export const SYSTEM_ROLE = {
+ role: 'system',
+ content: `- 사용자가 선택한 카테고리를 바탕으로 체크리스트 항목을 10개 생성합니다.
+ - 생성결과 형식은 JSON을 따릅니다.
+ - 각 항목의 어미는 ~하기, ~기로 끝나야합니다.
+ - json 형식은 다음과 같습니다.
+ {
+ "1": "생성된 체크리스트1",
+ "2": " 생성된 체크리스트2",
+ "3": "생성된 체크리스트3",
+ "4": "생성된 체크리스트4",
+ "5": "생성된 체크리스트5",
+ "6": "생성된 체크리스트6",
+ "7": "생성된 체크리스트7",
+ "8": "생성된 체크리스트8",
+ "9": "생성된 체크리스트9",
+ "10": "생성된 체크리스트10"
+ }
+ `,
+};
diff --git a/server/src/checklist-ai/dto/create-checklist-items.dto.ts b/server/src/checklist-ai/dto/create-checklist-items.dto.ts
new file mode 100644
index 00000000..06a5a144
--- /dev/null
+++ b/server/src/checklist-ai/dto/create-checklist-items.dto.ts
@@ -0,0 +1,27 @@
+import { IsNotEmpty, IsString } from 'class-validator';
+
+const mainCategories = [
+ //체크리스트 대 카테고리
+ '일상',
+ '여행',
+ '취미',
+ '공부',
+ '운동',
+ '기타',
+];
+
+export class CreateChecklistItemsDto {
+ // mainCategory에 있는 값은 mainCategories에 있는 값만 들어올 수 있도록
+ // @IsIn(mainCategories)
+ @IsString()
+ @IsNotEmpty()
+ mainCategory: string;
+
+ @IsString()
+ @IsNotEmpty()
+ subCategory: string;
+
+ @IsString()
+ @IsNotEmpty()
+ minorCategory: string;
+}
diff --git a/server/src/checklist-ai/entities/checklist-ai.entity.ts b/server/src/checklist-ai/entities/checklist-ai.entity.ts
new file mode 100644
index 00000000..d5bf158e
--- /dev/null
+++ b/server/src/checklist-ai/entities/checklist-ai.entity.ts
@@ -0,0 +1,17 @@
+// import { Column, Entity } from 'typeorm';
+// import { BaseModel } from '../../common/entity/base.entity';
+//
+// @Entity()
+// export class ChecklistAiEntity extends BaseModel {
+// @Column()
+// mainCategory: string;
+//
+// @Column()
+// subCategory: string;
+//
+// @Column()
+// minorCategory: string;
+//
+// @Column()
+// selectedCount: number;
+// }
diff --git a/server/src/common/common.controller.spec.ts b/server/src/common/common.controller.spec.ts
new file mode 100644
index 00000000..5db0f6bc
--- /dev/null
+++ b/server/src/common/common.controller.spec.ts
@@ -0,0 +1,20 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { CommonController } from './common.controller';
+import { CommonService } from './common.service';
+
+describe('CommonController', () => {
+ let controller: CommonController;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ controllers: [CommonController],
+ providers: [CommonService],
+ }).compile();
+
+ controller = module.get(CommonController);
+ });
+
+ it('should be defined', () => {
+ expect(controller).toBeDefined();
+ });
+});
diff --git a/server/src/common/common.controller.ts b/server/src/common/common.controller.ts
new file mode 100644
index 00000000..157070b7
--- /dev/null
+++ b/server/src/common/common.controller.ts
@@ -0,0 +1,7 @@
+import { Controller } from '@nestjs/common';
+import { CommonService } from './common.service';
+
+@Controller('common')
+export class CommonController {
+ constructor(private readonly commonService: CommonService) {}
+}
diff --git a/server/src/common/common.module.ts b/server/src/common/common.module.ts
new file mode 100644
index 00000000..46ae0b18
--- /dev/null
+++ b/server/src/common/common.module.ts
@@ -0,0 +1,9 @@
+import { Module } from '@nestjs/common';
+import { CommonService } from './common.service';
+import { CommonController } from './common.controller';
+
+@Module({
+ controllers: [CommonController],
+ providers: [CommonService],
+})
+export class CommonModule {}
diff --git a/server/src/common/common.service.spec.ts b/server/src/common/common.service.spec.ts
new file mode 100644
index 00000000..6ea5a77e
--- /dev/null
+++ b/server/src/common/common.service.spec.ts
@@ -0,0 +1,18 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { CommonService } from './common.service';
+
+describe('CommonService', () => {
+ let service: CommonService;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [CommonService],
+ }).compile();
+
+ service = module.get(CommonService);
+ });
+
+ it('should be defined', () => {
+ expect(service).toBeDefined();
+ });
+});
diff --git a/server/src/common/common.service.ts b/server/src/common/common.service.ts
new file mode 100644
index 00000000..f0369a5a
--- /dev/null
+++ b/server/src/common/common.service.ts
@@ -0,0 +1,4 @@
+import { Injectable } from '@nestjs/common';
+
+@Injectable()
+export class CommonService {}
diff --git a/server/src/common/entity/base.entity.ts b/server/src/common/entity/base.entity.ts
new file mode 100644
index 00000000..d84f2158
--- /dev/null
+++ b/server/src/common/entity/base.entity.ts
@@ -0,0 +1,12 @@
+import { CreateDateColumn, UpdateDateColumn } from 'typeorm';
+
+export abstract class BaseModel {
+ // @PrimaryGeneratedColumn()
+ // id: number;
+
+ @UpdateDateColumn()
+ updatedAt: Date;
+
+ @CreateDateColumn()
+ createdAt: Date;
+}
diff --git a/server/src/common/entity/checklist.entity.ts b/server/src/common/entity/checklist.entity.ts
new file mode 100644
index 00000000..ae986f30
--- /dev/null
+++ b/server/src/common/entity/checklist.entity.ts
@@ -0,0 +1,17 @@
+import { BaseModel } from './base.entity';
+// import { IsNumber } from 'class-validator';
+import { Column } from 'typeorm';
+
+export abstract class ChecklistModel extends BaseModel {
+ @Column()
+ title: string;
+
+ @Column({ nullable: true })
+ mainCategory: string;
+
+ @Column({ nullable: true })
+ subCategory: string;
+
+ @Column({ nullable: true })
+ minorCategory: string;
+}
diff --git a/server/src/common/interceptor/log.interceptor.ts b/server/src/common/interceptor/log.interceptor.ts
new file mode 100644
index 00000000..cfb96ae3
--- /dev/null
+++ b/server/src/common/interceptor/log.interceptor.ts
@@ -0,0 +1,58 @@
+import {
+ CallHandler,
+ ExecutionContext,
+ Inject,
+ Injectable,
+ NestInterceptor,
+} from '@nestjs/common';
+import { WinstonModule } from 'nest-winston';
+import { RedisClientType } from 'redis';
+import { Observable } from 'rxjs';
+import { tap } from 'rxjs/operators';
+import { winstonConfig } from '../../utils/winston.config';
+
+@Injectable()
+export class LoggingInterceptor implements NestInterceptor {
+ private readonly logger = WinstonModule.createLogger(winstonConfig);
+ constructor(
+ @Inject('REDIS_PUB_CLIENT')
+ private readonly redisPublisher: RedisClientType,
+ ) {}
+
+ intercept(context: ExecutionContext, next: CallHandler): Observable {
+ const ctx = context.switchToHttp();
+ const request = ctx.getRequest();
+ const response = ctx.getResponse();
+ const startTime = request['startTime'];
+ const reqBody = request['reqBody'];
+
+ return next.handle().pipe(
+ tap((data) => {
+ const endTime = Date.now();
+ const duration = endTime - startTime;
+ const { method, originalUrl, ip } = request;
+ const { statusCode } = response;
+ const startTimeString = new Date(startTime).toLocaleString('ko-KR', {
+ timeZone: 'Asia/Seoul',
+ });
+
+ const message = `${startTimeString} - ${method} ${originalUrl} - Status: ${statusCode} - IP: ${ip} - Duration: ${duration}ms`;
+ this.redisPublisher.publish(
+ 'httpLog',
+ JSON.stringify({
+ info: message,
+ req: reqBody,
+ res: data || {},
+ }),
+ );
+
+ this.logger.log({
+ level: 'info',
+ message: `${startTimeString} - ${method} ${originalUrl} - Status: ${statusCode} - IP: ${ip} - Duration: ${duration}ms - Request Body: ${JSON.stringify(
+ reqBody,
+ )} - Response Body: ${JSON.stringify(data)}`,
+ });
+ }),
+ );
+ }
+}
diff --git a/server/src/common/middlewares/logger.middleware.ts b/server/src/common/middlewares/logger.middleware.ts
new file mode 100644
index 00000000..caf71829
--- /dev/null
+++ b/server/src/common/middlewares/logger.middleware.ts
@@ -0,0 +1,17 @@
+import { Injectable, NestMiddleware } from '@nestjs/common';
+import { Request, Response, NextFunction } from 'express';
+import { WinstonModule } from 'nest-winston';
+import { winstonConfig } from '../../utils/winston.config';
+
+@Injectable()
+export class LoggerMiddleware implements NestMiddleware {
+ private readonly logger = WinstonModule.createLogger(winstonConfig);
+
+ use(req: Request, res: Response, next: NextFunction) {
+ const startTime = Date.now(); // 요청 시작 시간을 현재 시간으로 설정
+ req['startTime'] = startTime; // startTime을 req 객체에 저장
+ req['reqBody'] = req.body; // 요청 본문을 req 객체에 저장
+
+ next();
+ }
+}
diff --git a/server/src/feeds/entity/feed.entity.ts b/server/src/feeds/entity/feed.entity.ts
new file mode 100644
index 00000000..bbf90c59
--- /dev/null
+++ b/server/src/feeds/entity/feed.entity.ts
@@ -0,0 +1,14 @@
+import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
+import { PrivateChecklistModel } from '../../folders/private-checklists/entities/private-checklist.entity';
+
+@Entity()
+export class FeedModel extends PrivateChecklistModel {
+ @PrimaryGeneratedColumn()
+ feedId: number;
+
+ @Column({ default: 0 })
+ likeCount: number;
+
+ @Column({ default: 0 })
+ downloadCount: number;
+}
diff --git a/server/src/feeds/feeds.controller.ts b/server/src/feeds/feeds.controller.ts
new file mode 100644
index 00000000..a8c8b40d
--- /dev/null
+++ b/server/src/feeds/feeds.controller.ts
@@ -0,0 +1,22 @@
+import { Controller, Get, Param, Post, Query } from '@nestjs/common';
+import { FeedsService } from './feeds.service';
+
+@Controller('feeds')
+export class FeedsController {
+ constructor(private readonly feedsService: FeedsService) {}
+
+ @Get('category')
+ getAllFeedsByCategory(@Query('category') category: string) {
+ return this.feedsService.findAllFeedsByCategory(category);
+ }
+
+ @Post('like/:checklistId')
+ postLike(@Param('checklistId') id: number) {
+ return this.feedsService.updateLikeCount(id);
+ }
+
+ @Post('download/:checklistId')
+ postDownload(@Param('checklistId') id: number) {
+ return this.feedsService.updateDownloadCount(id);
+ }
+}
diff --git a/server/src/feeds/feeds.module.ts b/server/src/feeds/feeds.module.ts
new file mode 100644
index 00000000..dc1c0108
--- /dev/null
+++ b/server/src/feeds/feeds.module.ts
@@ -0,0 +1,12 @@
+import { Module } from '@nestjs/common';
+import { FeedsService } from './feeds.service';
+import { FeedsController } from './feeds.controller';
+import { TypeOrmModule } from '@nestjs/typeorm';
+import { FeedModel } from './entity/feed.entity';
+
+@Module({
+ imports: [TypeOrmModule.forFeature([FeedModel])],
+ controllers: [FeedsController],
+ providers: [FeedsService],
+})
+export class FeedsModule {}
diff --git a/server/src/feeds/feeds.service.spec.ts b/server/src/feeds/feeds.service.spec.ts
new file mode 100644
index 00000000..9c99b8c3
--- /dev/null
+++ b/server/src/feeds/feeds.service.spec.ts
@@ -0,0 +1,118 @@
+import { BadRequestException } from '@nestjs/common';
+import { Test, TestingModule } from '@nestjs/testing';
+import { getRepositoryToken } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+import { FeedModel } from './entity/feed.entity';
+import { FeedsService } from './feeds.service';
+
+type MockRepository = Partial, jest.Mock>>;
+
+describe('FeedsService', () => {
+ let service: FeedsService;
+ let mockFeedsRepository: MockRepository;
+
+ beforeEach(async () => {
+ mockFeedsRepository = {
+ findOne: jest.fn(),
+ find: jest.fn(),
+ save: jest.fn(),
+ };
+
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [
+ FeedsService,
+ {
+ provide: getRepositoryToken(FeedModel),
+ useValue: mockFeedsRepository,
+ },
+ ],
+ }).compile();
+
+ service = module.get(FeedsService);
+ });
+
+ it('findFeedById(feedId): 피드 ID로 피드를 찾는다', async () => {
+ const feedId = 1;
+ const mockFeed = { feedId, likeCount: 10, downloadCount: 5 };
+ mockFeedsRepository.findOne.mockResolvedValue(mockFeed);
+
+ const result = await service.findFeedById(feedId);
+
+ expect(mockFeedsRepository.findOne).toHaveBeenCalledWith({
+ where: { feedId },
+ });
+ expect(result).toEqual(mockFeed);
+ });
+
+ it('findFeedById(feedId): 존재하지 않는 피드 ID에 대한 예외 처리', async () => {
+ mockFeedsRepository.findOne.mockResolvedValue(undefined);
+
+ await expect(service.findFeedById(9999)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+
+ it('findAllFeedsByCategory(mainCategory): 주어진 카테고리의 모든 피드를 찾는다', async () => {
+ const mainCategory = 'Sports';
+ const mockFeeds = [
+ { feedId: 1, mainCategory },
+ { feedId: 2, mainCategory },
+ ];
+ mockFeedsRepository.find.mockResolvedValue(mockFeeds);
+
+ const result = await service.findAllFeedsByCategory(mainCategory);
+
+ expect(mockFeedsRepository.find).toHaveBeenCalledWith({
+ where: { mainCategory },
+ });
+ expect(result).toEqual(mockFeeds);
+ });
+
+ it('findAllFeedsByCategory(mainCategory): 주어진 카테고리에 해당하는 피드가 없을 경우 예외를 던진다', async () => {
+ const mainCategory = 'NonExistingCategory';
+ mockFeedsRepository.find.mockResolvedValue([]);
+
+ await expect(service.findAllFeedsByCategory(mainCategory)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+
+ it('updateLikeCount(feedId): 피드의 좋아요 수를 업데이트한다', async () => {
+ const feedId = 1;
+ const mockFeed = { feedId, likeCount: 10, downloadCount: 5 };
+ mockFeedsRepository.findOne.mockResolvedValue(mockFeed);
+ mockFeedsRepository.save.mockResolvedValue({ ...mockFeed, likeCount: 11 });
+
+ const result = await service.updateLikeCount(feedId);
+
+ expect(mockFeedsRepository.findOne).toHaveBeenCalledWith({
+ where: { feedId },
+ });
+ expect(mockFeedsRepository.save).toHaveBeenCalledWith({
+ ...mockFeed,
+ likeCount: 11,
+ });
+ expect(result.likeCount).toEqual(11);
+ });
+
+ it('updateDownloadCount(feedId): 피드의 다운로드 수를 업데이트한다', async () => {
+ const feedId = 1;
+ const mockFeed = { feedId, likeCount: 10, downloadCount: 5 };
+ mockFeedsRepository.findOne.mockResolvedValue(mockFeed);
+ mockFeedsRepository.save.mockResolvedValue({
+ ...mockFeed,
+ downloadCount: 6,
+ });
+
+ const result = await service.updateDownloadCount(feedId);
+
+ expect(mockFeedsRepository.findOne).toHaveBeenCalledWith({
+ where: { feedId },
+ });
+ expect(mockFeedsRepository.save).toHaveBeenCalledWith({
+ ...mockFeed,
+ downloadCount: 6,
+ });
+ expect(result.downloadCount).toEqual(6);
+ });
+});
diff --git a/server/src/feeds/feeds.service.ts b/server/src/feeds/feeds.service.ts
new file mode 100644
index 00000000..a8fd6024
--- /dev/null
+++ b/server/src/feeds/feeds.service.ts
@@ -0,0 +1,44 @@
+import { BadRequestException, Injectable } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { FeedModel } from './entity/feed.entity';
+import { Repository } from 'typeorm';
+
+@Injectable()
+export class FeedsService {
+ constructor(
+ @InjectRepository(FeedModel)
+ private readonly repository: Repository,
+ ) {}
+
+ async findFeedById(feedId: number) {
+ const feed = await this.repository.findOne({ where: { feedId } });
+ if (!feed) {
+ throw new BadRequestException(
+ `${feedId}는 존재하지 않는 피드 id 입니다.`,
+ );
+ }
+ return feed;
+ }
+
+ async findAllFeedsByCategory(mainCategory: string) {
+ const feed = await this.repository.find({ where: { mainCategory } });
+ if (feed.length === 0) {
+ throw new BadRequestException(
+ `${mainCategory}에 대한 피드가 존재하지 않습니다.`,
+ );
+ }
+ return feed;
+ }
+
+ async updateLikeCount(feedId: number) {
+ const feed = await this.findFeedById(feedId);
+ feed.likeCount += 1;
+ return this.repository.save(feed);
+ }
+
+ async updateDownloadCount(feedId: number) {
+ const feed = await this.findFeedById(feedId);
+ feed.downloadCount += 1;
+ return this.repository.save(feed);
+ }
+}
diff --git a/server/src/folders/dto/create-folder.dto.ts b/server/src/folders/dto/create-folder.dto.ts
new file mode 100644
index 00000000..33cea376
--- /dev/null
+++ b/server/src/folders/dto/create-folder.dto.ts
@@ -0,0 +1,8 @@
+import { IsNotEmpty, IsString } from 'class-validator';
+
+export class CreateFolderDto {
+ // 길이 제한 필요
+ @IsString()
+ @IsNotEmpty()
+ title: string;
+}
diff --git a/server/src/folders/dto/update-folder.dto.ts b/server/src/folders/dto/update-folder.dto.ts
new file mode 100644
index 00000000..0eb5e6f1
--- /dev/null
+++ b/server/src/folders/dto/update-folder.dto.ts
@@ -0,0 +1,4 @@
+import { PickType } from '@nestjs/mapped-types';
+import { CreateFolderDto } from './create-folder.dto';
+
+export class UpdateFolderDto extends PickType(CreateFolderDto, ['title']) {}
diff --git a/server/src/folders/entities/folder.entity.ts b/server/src/folders/entities/folder.entity.ts
new file mode 100644
index 00000000..5c02f464
--- /dev/null
+++ b/server/src/folders/entities/folder.entity.ts
@@ -0,0 +1,30 @@
+import {
+ Column,
+ Entity,
+ ManyToOne,
+ OneToMany,
+ PrimaryGeneratedColumn,
+} from 'typeorm';
+import { BaseModel } from '../../common/entity/base.entity';
+import { UserModel } from '../../users/entities/user.entity';
+import { PrivateChecklistModel } from '../private-checklists/entities/private-checklist.entity';
+
+@Entity()
+export class FolderModel extends BaseModel {
+ @PrimaryGeneratedColumn()
+ folderId: number;
+
+ @Column()
+ title: string;
+
+ @ManyToOne(() => UserModel, (user) => user.folders, {
+ nullable: false,
+ })
+ owner: UserModel;
+
+ @OneToMany(
+ () => PrivateChecklistModel,
+ (privateChecklist) => privateChecklist.folder,
+ )
+ privateChecklists: PrivateChecklistModel[];
+}
diff --git a/server/src/folders/folders.controller.ts b/server/src/folders/folders.controller.ts
new file mode 100644
index 00000000..e08ae630
--- /dev/null
+++ b/server/src/folders/folders.controller.ts
@@ -0,0 +1,50 @@
+import {
+ Body,
+ Controller,
+ Delete,
+ Get,
+ Param,
+ Post,
+ Put,
+} from '@nestjs/common';
+import { UserId } from 'src/users/decorator/userId.decorator';
+import { CreateFolderDto } from './dto/create-folder.dto';
+import { UpdateFolderDto } from './dto/update-folder.dto';
+import { FoldersService } from './folders.service';
+
+@Controller('folders')
+export class FoldersController {
+ constructor(private readonly foldersService: FoldersService) {}
+
+ @Post()
+ postFolder(
+ @UserId() userId: number,
+ @Body() createFolderDto: CreateFolderDto,
+ ) {
+ return this.foldersService.createFolder(userId, createFolderDto);
+ }
+
+ @Get()
+ getFolders(@UserId() userId: number) {
+ return this.foldersService.findAllFolders(userId);
+ }
+
+ @Get(':folderId')
+ getFolder(@Param('folderId') folderId: number, @UserId() userId: number) {
+ return this.foldersService.findFolderById(folderId, userId);
+ }
+
+ @Put(':folderId')
+ putFolder(
+ @Param('folderId') folderId: number,
+ @UserId() userId: number,
+ @Body() updateFolderDto: UpdateFolderDto,
+ ) {
+ return this.foldersService.updateFolder(folderId, userId, updateFolderDto);
+ }
+
+ @Delete(':folderId')
+ deleteFolder(@Param('folderId') folderId: number, @UserId() userId: number) {
+ return this.foldersService.removeFolder(folderId, userId);
+ }
+}
diff --git a/server/src/folders/folders.module.ts b/server/src/folders/folders.module.ts
new file mode 100644
index 00000000..6826471c
--- /dev/null
+++ b/server/src/folders/folders.module.ts
@@ -0,0 +1,14 @@
+import { Module } from '@nestjs/common';
+import { FoldersService } from './folders.service';
+import { FoldersController } from './folders.controller';
+import { TypeOrmModule } from '@nestjs/typeorm';
+import { FolderModel } from './entities/folder.entity';
+import { UsersModule } from '../users/users.module';
+
+@Module({
+ imports: [TypeOrmModule.forFeature([FolderModel]), UsersModule],
+ controllers: [FoldersController],
+ providers: [FoldersService],
+ exports: [FoldersService],
+})
+export class FoldersModule {}
diff --git a/server/src/folders/folders.service.spec.ts b/server/src/folders/folders.service.spec.ts
new file mode 100644
index 00000000..4cedc94d
--- /dev/null
+++ b/server/src/folders/folders.service.spec.ts
@@ -0,0 +1,196 @@
+import { BadRequestException } from '@nestjs/common';
+import { Test, TestingModule } from '@nestjs/testing';
+import { getRepositoryToken } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+import { UserModel } from '../users/entities/user.entity';
+import { UsersService } from '../users/users.service';
+import { CreateFolderDto } from './dto/create-folder.dto';
+import { UpdateFolderDto } from './dto/update-folder.dto';
+import { FolderModel } from './entities/folder.entity';
+import { FoldersService } from './folders.service';
+
+type MockRepository = Partial, jest.Mock>>;
+
+describe('FoldersService', () => {
+ let service: FoldersService;
+ let mockFoldersRepository: MockRepository;
+ let mockUsersRepository: MockRepository;
+
+ beforeEach(async () => {
+ mockFoldersRepository = {
+ create: jest.fn(),
+ save: jest.fn(),
+ findOne: jest.fn(),
+ find: jest.fn(),
+ remove: jest.fn(),
+ exist: jest.fn(),
+ };
+
+ mockUsersRepository = {
+ findOne: jest.fn(),
+ };
+
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [
+ FoldersService,
+ UsersService,
+ {
+ provide: getRepositoryToken(FolderModel),
+ useValue: mockFoldersRepository,
+ },
+ {
+ provide: getRepositoryToken(UserModel),
+ useValue: mockUsersRepository,
+ },
+ ],
+ }).compile();
+
+ service = module.get(FoldersService);
+ });
+
+ it('service.createFolder(createFolderDto) : 새로운 폴더를 생성한다.', async () => {
+ const createFolderDto: CreateFolderDto = {
+ title: 'blackpink in your area',
+ };
+ const user = new UserModel(); // 새로운 UserModel 인스턴스 생성
+ mockUsersRepository.findOne.mockResolvedValue(user); // 존재하는 사용자를 반환
+ mockFoldersRepository.exist.mockResolvedValue(false);
+
+ // createFolderDto와 owner를 포함한 객체를 create 메서드에 전달
+ const expectedFolderObject = {
+ ...createFolderDto,
+ owner: user,
+ };
+ mockFoldersRepository.create.mockReturnValue(expectedFolderObject);
+ mockFoldersRepository.save.mockResolvedValue({
+ folderId: 1,
+ ...expectedFolderObject,
+ });
+
+ const result = await service.createFolder(1, createFolderDto);
+
+ expect(mockFoldersRepository.exist).toHaveBeenCalledWith({
+ where: { title: createFolderDto.title },
+ });
+ expect(mockFoldersRepository.create).toHaveBeenCalledWith(
+ expectedFolderObject,
+ ); // 수정된 부분
+ expect(mockFoldersRepository.save).toHaveBeenCalledWith(
+ expectedFolderObject,
+ ); // 수정된 부분
+ expect(result).toEqual({ folderId: 1, ...createFolderDto });
+ });
+
+ it('service.createFolder(createFolderDto) : 이미 존재하는 폴더명일 경우 BadRequestException을 던진다.', async () => {
+ const createFolderDto: CreateFolderDto = {
+ title: 'blackpink in your area',
+ };
+ mockUsersRepository.findOne.mockResolvedValue(new UserModel()); // 존재하는 사용자를 반환
+ mockFoldersRepository.exist.mockResolvedValue(true);
+
+ await expect(service.createFolder(1, createFolderDto)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+
+ it('service.createFolder(createFolderDto) : 존재하지 않는 사용자일 경우 BadRequestException을 던진다.', async () => {
+ const createFolderDto: CreateFolderDto = {
+ title: 'new folder',
+ };
+ mockUsersRepository.findOne.mockResolvedValue(null); // 존재하지 않는 사용자를 반환
+
+ await expect(service.createFolder(1, createFolderDto)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+
+ it('service.findAllFolders() : 모든 폴더를 찾는다.', async () => {
+ const mockFolders = [
+ { folderId: 1, email: 'test@example.com', nickname: 'TestFolder' },
+ { folderId: 2, email: 'test2@example.com', nickname: 'TestFolder2' },
+ ];
+ mockFoldersRepository.find.mockResolvedValue(mockFolders);
+
+ const result = await service.findAllFolders(1);
+
+ expect(mockFoldersRepository.find).toHaveBeenCalled();
+ expect(result).toEqual(mockFolders);
+ });
+
+ it('service.findFolderById(id) : folderId에 해당하는 폴더를 찾는다.', async () => {
+ const folder = { folderId: 1, title: 'blackpink in your area' };
+ mockFoldersRepository.findOne.mockResolvedValue(folder);
+
+ const result = await service.findFolderById(1, 1);
+
+ expect(mockFoldersRepository.findOne).toHaveBeenCalledWith({
+ where: { folderId: 1, owner: { userId: 1 } },
+ });
+ expect(result).toEqual(folder);
+ });
+
+ it('service.findFolderById(folderId) : 존재하지 않는 폴더명일 경우 BadRequestException을 던진다.', async () => {
+ mockFoldersRepository.findOne.mockResolvedValue(null);
+
+ await expect(service.findFolderById(1, 1)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+
+ it('service.updateFolder(folderId, updateFolderDto) : folderId에 해당하는 폴더를 업데이트한다.', async () => {
+ const updateFolderDto: UpdateFolderDto = {
+ title: 'newJeans in your area',
+ };
+ const existingFolder = {
+ folderId: 1,
+ title: 'blackpink in your area',
+ };
+ mockFoldersRepository.findOne.mockResolvedValue(existingFolder);
+ mockFoldersRepository.save.mockResolvedValue({
+ ...existingFolder,
+ ...updateFolderDto,
+ });
+
+ const result = await service.updateFolder(1, 1, updateFolderDto);
+
+ expect(mockFoldersRepository.findOne).toHaveBeenCalledWith({
+ where: { folderId: 1, owner: { userId: 1 } },
+ });
+ expect(mockFoldersRepository.save).toHaveBeenCalledWith({
+ ...existingFolder,
+ ...updateFolderDto,
+ });
+ expect(result.title).toEqual('newJeans in your area');
+ });
+
+ it('service.updateFolder(folderId, updateFolderDto) : 존재하지 않는 폴더 ID에 대한 처리를 검증한다.', async () => {
+ const updateFolderDto: UpdateFolderDto = { title: 'UpdatedFolder' };
+ mockFoldersRepository.findOne.mockResolvedValueOnce(null); // 폴더가 존재하지 않는다고 가정
+
+ await expect(
+ service.updateFolder(9999, 1, updateFolderDto),
+ ).rejects.toThrow(BadRequestException);
+ });
+
+ it('service.removeFolder(folderId) : folderId에 해당하는 폴더를 삭제한다.', async () => {
+ const folder = { folderId: 1, title: 'blackpink in your area' };
+ mockFoldersRepository.findOne.mockResolvedValue(folder);
+ mockFoldersRepository.remove.mockResolvedValue(folder);
+
+ const result = await service.removeFolder(1, 1);
+
+ expect(mockFoldersRepository.findOne).toHaveBeenCalledWith({
+ where: { folderId: 1, owner: { userId: 1 } },
+ });
+ expect(mockFoldersRepository.remove).toHaveBeenCalledWith(folder);
+ expect(result).toEqual({ message: '삭제되었습니다.' });
+ });
+
+ it('service.removeFolder(folderId) : 존재하지 않는 폴더 ID에 대한 처리를 검증한다.', async () => {
+ mockFoldersRepository.findOne.mockResolvedValueOnce(null); // 폴더가 존재하지 않는다고 가정
+
+ await expect(service.removeFolder(9999, 1)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+});
diff --git a/server/src/folders/folders.service.ts b/server/src/folders/folders.service.ts
new file mode 100644
index 00000000..bd0e8759
--- /dev/null
+++ b/server/src/folders/folders.service.ts
@@ -0,0 +1,98 @@
+import { BadRequestException, Injectable } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+import { UsersService } from '../users/users.service';
+import { CreateFolderDto } from './dto/create-folder.dto';
+import { UpdateFolderDto } from './dto/update-folder.dto';
+import { FolderModel } from './entities/folder.entity';
+
+@Injectable()
+export class FoldersService {
+ constructor(
+ @InjectRepository(FolderModel)
+ private readonly folderRepository: Repository,
+ private readonly usersService: UsersService,
+ ) {}
+
+ /**
+ * 사용자 ID와 폴더 생성 DTO를 받아 새로운 폴더를 생성한다.
+ * @param userId 사용자 식별자
+ * @param dto 폴더 생성에 필요한 데이터 전송 객체
+ * @returns 생성된 폴더 객체
+ */
+ async createFolder(userId: number, dto: CreateFolderDto) {
+ const owner = await this.usersService.findUserById(userId);
+ const folderObject = this.folderRepository.create({
+ ...dto,
+ owner,
+ });
+ const folderExists = await this.folderRepository.exist({
+ where: {
+ title: dto.title,
+ },
+ });
+ if (folderExists) {
+ throw new BadRequestException('이미 존재하는 폴더입니다.');
+ }
+ const newFolder = await this.folderRepository.save(folderObject);
+ delete newFolder.owner; // owner 필드를 삭제
+
+ return newFolder;
+ }
+
+ /**
+ * 주어진 사용자 ID에 해당하는 모든 폴더를 찾아 반환한다.
+ * @param userId 사용자 식별자
+ * @returns 해당 사용자의 폴더 배열
+ */
+ async findAllFolders(userId: number) {
+ const folders = await this.folderRepository.find({
+ where: { owner: { userId: userId } },
+ });
+ return folders;
+ }
+
+ /**
+ * 폴더 ID와 사용자 ID를 기반으로 특정 폴더를 찾아 반환한다.
+ * @param folderId 폴더 식별자
+ * @param userId 사용자 식별자
+ * @returns 찾아진 폴더 객체
+ */
+ async findFolderById(folderId: number, userId: number) {
+ const folder = await this.folderRepository.findOne({
+ where: { folderId, owner: { userId } },
+ });
+ if (!folder) {
+ throw new BadRequestException('존재하지 않는 폴더입니다.');
+ }
+ return folder;
+ }
+
+ /**
+ * 폴더 ID, 사용자 ID, 업데이트할 폴더 데이터를 받아 해당 폴더의 정보를 업데이트한다.
+ * @param folderId 업데이트할 폴더의 식별자
+ * @param userId 사용자 식별자
+ * @param dto 폴더 업데이트에 필요한 데이터 전송 객체
+ * @returns 업데이트된 폴더 객체
+ */
+ async updateFolder(folderId: number, userId: number, dto: UpdateFolderDto) {
+ const folder = await this.findFolderById(folderId, userId);
+ const updatedFolder = await this.folderRepository.save({
+ ...folder,
+ ...dto,
+ });
+ return updatedFolder;
+ }
+
+ /**
+ * 폴더 ID와 사용자 ID를 사용하여 특정 폴더를 삭제한다.
+ * @param folderId 삭제할 폴더의 식별자
+ * @param userId 사용자 식별자
+ * @returns 삭제 성공 메시지
+ */
+ async removeFolder(folderId: number, userId: number) {
+ const folder = await this.findFolderById(folderId, userId);
+ await this.folderRepository.remove(folder);
+ return { message: '삭제되었습니다.' };
+ }
+}
diff --git a/server/src/folders/private-checklists/dto/create-private-checklist.dto.ts b/server/src/folders/private-checklists/dto/create-private-checklist.dto.ts
new file mode 100644
index 00000000..f26867cf
--- /dev/null
+++ b/server/src/folders/private-checklists/dto/create-private-checklist.dto.ts
@@ -0,0 +1,20 @@
+import { PartialType } from '@nestjs/mapped-types';
+import { Type } from 'class-transformer';
+import { IsArray, IsNotEmpty, IsString, ValidateNested } from 'class-validator';
+import {
+ ChecklistItem,
+ PrivateChecklistModel,
+} from '../entities/private-checklist.entity';
+
+export class CreatePrivateChecklistDto extends PartialType(
+ PrivateChecklistModel,
+) {
+ @IsString()
+ @IsNotEmpty()
+ title: string;
+
+ @IsArray()
+ @ValidateNested({ each: true })
+ @Type(() => ChecklistItem)
+ items: ChecklistItem[];
+}
diff --git a/server/src/folders/private-checklists/dto/update-private-checklist.dto.ts b/server/src/folders/private-checklists/dto/update-private-checklist.dto.ts
new file mode 100644
index 00000000..d56af75d
--- /dev/null
+++ b/server/src/folders/private-checklists/dto/update-private-checklist.dto.ts
@@ -0,0 +1,33 @@
+import { PartialType } from '@nestjs/mapped-types';
+import { Type } from 'class-transformer';
+import {
+ IsArray,
+ IsNotEmpty,
+ IsNumber,
+ IsOptional,
+ IsString,
+ ValidateNested,
+} from 'class-validator';
+import {
+ ChecklistItem,
+ PrivateChecklistModel,
+} from '../entities/private-checklist.entity';
+
+export class UpdatePrivateChecklistDto extends PartialType(
+ PrivateChecklistModel,
+) {
+ @IsString()
+ @IsNotEmpty()
+ @IsOptional()
+ title?: string;
+
+ @IsNumber()
+ @IsOptional()
+ folderId?: number;
+
+ @IsArray()
+ @ValidateNested({ each: true })
+ @Type(() => ChecklistItem)
+ @IsOptional()
+ items?: ChecklistItem[];
+}
diff --git a/server/src/folders/private-checklists/entities/private-checklist.entity.ts b/server/src/folders/private-checklists/entities/private-checklist.entity.ts
new file mode 100644
index 00000000..1f0c2d89
--- /dev/null
+++ b/server/src/folders/private-checklists/entities/private-checklist.entity.ts
@@ -0,0 +1,32 @@
+import { IsBoolean, IsString } from 'class-validator';
+import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
+import { ChecklistModel } from '../../../common/entity/checklist.entity';
+import { UserModel } from '../../../users/entities/user.entity';
+import { FolderModel } from '../../entities/folder.entity';
+
+export class ChecklistItem {
+ @IsBoolean()
+ isChecked: boolean;
+
+ @IsString()
+ value: string;
+}
+
+@Entity()
+export class PrivateChecklistModel extends ChecklistModel {
+ @PrimaryGeneratedColumn()
+ privateChecklistId: number;
+
+ @ManyToOne(() => UserModel, (user) => user.privateChecklists, {
+ nullable: false,
+ })
+ editor: UserModel;
+
+ @ManyToOne(() => FolderModel, (folder) => folder.privateChecklists, {
+ nullable: false,
+ })
+ folder: FolderModel;
+
+ @Column({ type: 'json' })
+ items: ChecklistItem[];
+}
diff --git a/server/src/folders/private-checklists/private-checklists.controller.ts b/server/src/folders/private-checklists/private-checklists.controller.ts
new file mode 100644
index 00000000..e9755923
--- /dev/null
+++ b/server/src/folders/private-checklists/private-checklists.controller.ts
@@ -0,0 +1,103 @@
+import {
+ Body,
+ Controller,
+ Delete,
+ Get,
+ Param,
+ Post,
+ Put,
+} from '@nestjs/common';
+import { UserId } from 'src/users/decorator/userId.decorator';
+import { CreatePrivateChecklistDto } from './dto/create-private-checklist.dto';
+import { UpdatePrivateChecklistDto } from './dto/update-private-checklist.dto';
+import { PrivateChecklistsService } from './private-checklists.service';
+
+@Controller('folders/:folderId/checklists')
+export class PrivateChecklistsController {
+ constructor(private readonly checklistsService: PrivateChecklistsService) {}
+
+ /**
+ * @description userId와 folderId와 title을 통해 해당 folder에 새로운 checklist를 생성합니다.
+ * @param {number} folderId
+ * @param {CreatePrivateChecklistDto} dto
+ * @returns {Promise}
+ */
+ @Post()
+ postPrivateChecklist(
+ @Param('folderId') folderId: number,
+ @UserId() userId: number,
+ @Body() dto: CreatePrivateChecklistDto,
+ ) {
+ return this.checklistsService.createPrivateChecklist(folderId, userId, dto);
+ }
+
+ /**
+ * @description folderId를 통해 해당 folder의 모든 checklist를 조회합니다.
+ * @param {number} folderId
+ * @returns {Promise}
+ */
+ @Get()
+ getAllPrivateChecklists(
+ @Param('folderId') folderId: number,
+ @UserId() userId: number,
+ ) {
+ return this.checklistsService.findAllPrivateChecklists(folderId, userId);
+ }
+
+ /**
+ * @description checklistId를 통해 해당 checklist를 조회합니다.
+ * @param {number} privateChecklistId
+ * @returns {Promise}
+ */
+ @Get(':privateChecklistId')
+ getPrivateChecklist(
+ @Param('folderId') folderId: number,
+ @Param('privateChecklistId') privateChecklistId: number,
+ @UserId() userId: number,
+ ) {
+ return this.checklistsService.findPrivateChecklistById(
+ folderId,
+ privateChecklistId,
+ userId,
+ );
+ }
+
+ /**
+ * @description checklistId를 통해 해당 checklist의 title을 수정합니다.
+ * @param {number} privateChecklistId
+ * @param {UpdatePrivateChecklistDto} dto
+ * @returns {Promise}
+ */
+ @Put(':privateChecklistId')
+ putPrivateChecklist(
+ @Param('folderId') folderId: number,
+ @Param('privateChecklistId') privateChecklistId: number,
+ @UserId() userId: number,
+ @Body() dto: UpdatePrivateChecklistDto,
+ ) {
+ return this.checklistsService.updatePrivateChecklist(
+ folderId,
+ privateChecklistId,
+ userId,
+ dto,
+ );
+ }
+
+ /**
+ * @description checklistId를 통해 해당 checklist를 삭제합니다.
+ * @param {number} privateChecklistId
+ * @returns {Promise}
+ */
+ @Delete(':privateChecklistId')
+ deletePrivateChecklist(
+ @Param('folderId') folderId: number,
+ @Param('privateChecklistId') privateChecklistId: number,
+ @UserId() userId: number,
+ ) {
+ return this.checklistsService.removePrivateChecklist(
+ folderId,
+ privateChecklistId,
+ userId,
+ );
+ }
+}
diff --git a/server/src/folders/private-checklists/private-checklists.module.ts b/server/src/folders/private-checklists/private-checklists.module.ts
new file mode 100644
index 00000000..9e729c0b
--- /dev/null
+++ b/server/src/folders/private-checklists/private-checklists.module.ts
@@ -0,0 +1,18 @@
+import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+import { UsersModule } from '../../users/users.module';
+import { FoldersModule } from '../folders.module';
+import { PrivateChecklistModel } from './entities/private-checklist.entity';
+import { PrivateChecklistsController } from './private-checklists.controller';
+import { PrivateChecklistsService } from './private-checklists.service';
+
+@Module({
+ imports: [
+ TypeOrmModule.forFeature([PrivateChecklistModel]),
+ FoldersModule,
+ UsersModule,
+ ],
+ controllers: [PrivateChecklistsController],
+ providers: [PrivateChecklistsService],
+})
+export class ChecklistsModule {}
diff --git a/server/src/folders/private-checklists/private-checklists.service.spec.ts b/server/src/folders/private-checklists/private-checklists.service.spec.ts
new file mode 100644
index 00000000..9b9c5434
--- /dev/null
+++ b/server/src/folders/private-checklists/private-checklists.service.spec.ts
@@ -0,0 +1,223 @@
+import { BadRequestException } from '@nestjs/common';
+import { Test, TestingModule } from '@nestjs/testing';
+import { getRepositoryToken } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+import { UserModel } from '../../users/entities/user.entity';
+import { UsersService } from '../../users/users.service';
+import { FolderModel } from '../entities/folder.entity';
+import { FoldersService } from '../folders.service';
+import { CreatePrivateChecklistDto } from './dto/create-private-checklist.dto';
+import { UpdatePrivateChecklistDto } from './dto/update-private-checklist.dto';
+import { PrivateChecklistModel } from './entities/private-checklist.entity';
+import { PrivateChecklistsService } from './private-checklists.service';
+
+type MockRepository = Partial, jest.Mock>>;
+
+describe('PrivateChecklistsService', () => {
+ let service: PrivateChecklistsService;
+ let mockChecklistRepository: MockRepository;
+ let mockFoldersService: Partial;
+ let mockUsersService: Partial;
+ let mockFoldersRepository: MockRepository;
+ let mockUsersRepository: MockRepository;
+
+ beforeEach(async () => {
+ mockChecklistRepository = {
+ create: jest.fn(),
+ save: jest.fn(),
+ findOne: jest.fn(),
+ find: jest.fn(),
+ remove: jest.fn(),
+ };
+
+ mockUsersService = {
+ findUserById: jest.fn().mockResolvedValue(new UserModel()),
+ };
+
+ mockFoldersService = {
+ findFolderById: jest.fn().mockResolvedValue(new FolderModel()),
+ };
+
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [
+ PrivateChecklistsService,
+ FoldersService,
+ UsersService,
+ {
+ provide: getRepositoryToken(PrivateChecklistModel),
+ useValue: mockChecklistRepository,
+ },
+ {
+ provide: getRepositoryToken(FolderModel),
+ useValue: mockFoldersRepository,
+ },
+ {
+ provide: getRepositoryToken(UserModel),
+ useValue: mockUsersRepository,
+ },
+ {
+ provide: UsersService,
+ useValue: mockUsersService,
+ },
+ {
+ provide: FoldersService,
+ useValue: mockFoldersService,
+ },
+ ],
+ }).compile();
+
+ service = module.get(PrivateChecklistsService);
+ });
+
+ it('service.createPrivateChecklist(createPrivateChecklistDto) : 새로운 체크리스트를 생성한다.', async () => {
+ const user = new UserModel();
+ const folder = new FolderModel();
+ const createDto = new CreatePrivateChecklistDto();
+ const expectedChecklistObject = {
+ ...createDto,
+ editor: { userId: 1 },
+ folder: { folderId: 1 },
+ };
+
+ mockChecklistRepository.create.mockReturnValue(expectedChecklistObject);
+ mockChecklistRepository.save.mockResolvedValue(expectedChecklistObject);
+
+ const result = await service.createPrivateChecklist(1, 1, createDto);
+
+ expect(mockFoldersService.findFolderById).toHaveBeenCalledWith(1, 1);
+
+ expect(mockChecklistRepository.create).toHaveBeenCalledWith(
+ expectedChecklistObject,
+ );
+ expect(mockChecklistRepository.save).toHaveBeenCalledWith(
+ expectedChecklistObject,
+ );
+ expect(result).toEqual(expectedChecklistObject);
+ });
+
+ it('service.findAllPrivateChecklists() : 모든 체크리스트를 찾는다.', async () => {
+ const checklists = [
+ new PrivateChecklistModel(),
+ new PrivateChecklistModel(),
+ ];
+ mockChecklistRepository.find.mockResolvedValue(checklists);
+
+ const result = await service.findAllPrivateChecklists(1, 1);
+
+ expect(mockChecklistRepository.find).toHaveBeenCalledWith({
+ where: { folder: { folderId: 1 }, editor: { userId: 1 } },
+ });
+ expect(result).toEqual(checklists);
+ });
+
+ it('service.findPrivateChecklistById(privateChecklistId) : privateChecklistId에 해당하는 체크리스트를 찾는다.', async () => {
+ const checklist = new PrivateChecklistModel();
+ mockChecklistRepository.findOne.mockResolvedValue(checklist);
+
+ const result = await service.findPrivateChecklistById(1, 1, 1);
+
+ expect(mockChecklistRepository.findOne).toHaveBeenCalledWith({
+ where: {
+ privateChecklistId: 1,
+ folder: { folderId: 1 },
+ editor: { userId: 1 },
+ },
+ });
+ expect(result).toEqual(checklist);
+ });
+
+ it('service.findPrivateChecklistById(privateChecklistId) : 존재하지 않는 체크리스트일 경우 BadRequestException을 던진다.', async () => {
+ mockChecklistRepository.findOne.mockResolvedValue(null);
+
+ await expect(service.findPrivateChecklistById(1, 1, 1)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+
+ it('service.updatePrivateChecklist(privateChecklistId, updateDto) : 체크리스트를 업데이트한다.', async () => {
+ const updateDto = new UpdatePrivateChecklistDto();
+ const existingChecklist = new PrivateChecklistModel();
+ mockChecklistRepository.findOne.mockResolvedValue(existingChecklist);
+ mockChecklistRepository.save.mockResolvedValue({
+ ...existingChecklist,
+ ...updateDto,
+ });
+
+ const result = await service.updatePrivateChecklist(1, 1, 1, updateDto);
+
+ expect(mockChecklistRepository.findOne).toHaveBeenCalledWith({
+ where: {
+ privateChecklistId: 1,
+ folder: { folderId: 1 },
+ editor: { userId: 1 },
+ },
+ });
+ expect(mockChecklistRepository.save).toHaveBeenCalledWith({
+ ...existingChecklist,
+ ...updateDto,
+ });
+ expect(result).toEqual({ ...existingChecklist, ...updateDto });
+ });
+
+ it('service.updatePrivateChecklist(privateChecklistId, updateDto) : title만 업데이트한다.', async () => {
+ const updateDto = new UpdatePrivateChecklistDto();
+ updateDto.title = 'Updated Title';
+ const existingChecklist = new PrivateChecklistModel();
+ existingChecklist.title = 'Original Title';
+
+ mockChecklistRepository.findOne.mockResolvedValue(existingChecklist);
+ mockChecklistRepository.save.mockResolvedValue({
+ ...existingChecklist,
+ ...updateDto,
+ });
+
+ const result = await service.updatePrivateChecklist(1, 1, 1, updateDto);
+
+ expect(mockChecklistRepository.findOne).toHaveBeenCalledWith({
+ where: {
+ privateChecklistId: 1,
+ folder: { folderId: 1 },
+ editor: { userId: 1 },
+ },
+ });
+ expect(mockChecklistRepository.save).toHaveBeenCalledWith({
+ ...existingChecklist,
+ title: updateDto.title, // title이 업데이트되었는지 확인
+ });
+ expect(result.title).toEqual(updateDto.title); // 결과의 title이 업데이트된 title과 일치하는지 확인
+ });
+
+ it('service.updatePrivateChecklist(privateChecklistId, updateDto) : 존재하지 않는 체크리스트일 경우 BadRequestException을 던진다.', async () => {
+ const updateDto = new UpdatePrivateChecklistDto();
+ mockChecklistRepository.findOne.mockResolvedValue(null);
+
+ await expect(
+ service.updatePrivateChecklist(1, 1, 1, updateDto),
+ ).rejects.toThrow(BadRequestException);
+ });
+
+ it('service.removePrivateChecklist(privateChecklistId) : 체크리스트를 삭제한다.', async () => {
+ const checklist = new PrivateChecklistModel();
+ mockChecklistRepository.findOne.mockResolvedValue(checklist);
+
+ const result = await service.removePrivateChecklist(1, 1, 1);
+
+ expect(mockChecklistRepository.findOne).toHaveBeenCalledWith({
+ where: {
+ privateChecklistId: 1,
+ folder: { folderId: 1 },
+ editor: { userId: 1 },
+ },
+ });
+ expect(mockChecklistRepository.remove).toHaveBeenCalledWith(checklist);
+ expect(result).toEqual({ message: '삭제되었습니다.' });
+ });
+
+ it('service.removePrivateChecklist(privateChecklistId) : 존재하지 않는 체크리스트일 경우 BadRequestException을 던진다.', async () => {
+ mockChecklistRepository.findOne.mockResolvedValue(null);
+
+ await expect(service.removePrivateChecklist(1, 1, 1)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+});
diff --git a/server/src/folders/private-checklists/private-checklists.service.ts b/server/src/folders/private-checklists/private-checklists.service.ts
new file mode 100644
index 00000000..79e364f6
--- /dev/null
+++ b/server/src/folders/private-checklists/private-checklists.service.ts
@@ -0,0 +1,110 @@
+import { BadRequestException, Injectable } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+import { FoldersService } from '../folders.service';
+import { CreatePrivateChecklistDto } from './dto/create-private-checklist.dto';
+import { UpdatePrivateChecklistDto } from './dto/update-private-checklist.dto';
+import { PrivateChecklistModel } from './entities/private-checklist.entity';
+
+@Injectable()
+export class PrivateChecklistsService {
+ constructor(
+ @InjectRepository(PrivateChecklistModel)
+ private readonly repository: Repository,
+ private readonly foldersService: FoldersService, // private readonly usersService: UsersService,
+ ) {}
+
+ async createPrivateChecklist(
+ folderId: number,
+ userId: number,
+ dto: CreatePrivateChecklistDto,
+ ) {
+ // 1. folderId를 통해 해당 folder가 존재하는지 확인합니다.
+ // userId를 통해 user entity를 가져옵니다.
+ const folder = await this.foldersService.findFolderById(folderId, userId);
+ // const user = await this.usersService.findUserById(userId);
+
+ // 3. 새로운 checklist를 생성합니다.
+ const newChecklist = this.repository.create({
+ ...dto,
+ editor: { userId },
+ folder: { folderId },
+ });
+
+ // 4. 생성된 checklist를 저장하고, 해당 checklist를 반환합니다.
+ return this.repository.save(newChecklist);
+ }
+
+ async findAllPrivateChecklists(folderId: number, userId: number) {
+ const checklists = await this.repository.find({
+ where: { folder: { folderId }, editor: { userId } },
+ });
+ return checklists;
+ }
+
+ async findPrivateChecklistById(
+ folderId: number,
+ privateChecklistId: number,
+ userId: number,
+ ) {
+ const checklist = await this.repository.findOne({
+ where: { privateChecklistId, folder: { folderId }, editor: { userId } },
+ });
+ if (!checklist) {
+ throw new BadRequestException('존재하지 않는 체크리스트입니다.');
+ }
+ return checklist;
+ }
+
+ async updatePrivateChecklist(
+ folderId: number,
+ privateChecklistId: number,
+ userId: number,
+ dto: UpdatePrivateChecklistDto,
+ ) {
+ const { title, folderId: newFolderId, items } = dto;
+ const checklist = await this.findPrivateChecklistById(
+ folderId,
+ privateChecklistId,
+ userId,
+ );
+ if (!checklist) {
+ throw new BadRequestException('존재하지 않는 체크리스트입니다.');
+ }
+
+ if (title) {
+ checklist.title = title;
+ }
+
+ if (newFolderId) {
+ const folder = await this.foldersService.findFolderById(
+ newFolderId,
+ userId,
+ );
+ checklist.folder = folder;
+ }
+
+ if (items) {
+ checklist.items = items;
+ }
+
+ const newChecklist = await this.repository.save(checklist);
+ return newChecklist;
+ }
+
+ async removePrivateChecklist(
+ folderId: number,
+ privateChecklistId: number,
+ userId: number,
+ ) {
+ const checklist = await this.findPrivateChecklistById(
+ folderId,
+ privateChecklistId,
+ userId,
+ );
+
+ // soft-delete 방식으로 수정필요
+ await this.repository.remove(checklist);
+ return { message: '삭제되었습니다.' };
+ }
+}
diff --git a/server/src/main.ts b/server/src/main.ts
new file mode 100644
index 00000000..1108ec65
--- /dev/null
+++ b/server/src/main.ts
@@ -0,0 +1,39 @@
+import { ValidationPipe } from '@nestjs/common';
+import { NestFactory } from '@nestjs/core';
+import { WsAdapter } from '@nestjs/platform-ws';
+import * as cookieParser from 'cookie-parser';
+import { AppModule } from './app.module';
+import { AuthService } from './auth/auth.service';
+import { AccessTokenGuard } from './auth/guard/access-token.guard';
+
+async function bootstrap() {
+ const app = await NestFactory.create(AppModule);
+ app.use(cookieParser());
+
+ //cors 설정 (개발용)
+ app.enableCors({
+ origin: ['http://localhost:5500', 'http://localhost:8080'],
+ credentials: true, // 쿠키와 함께 요청을 허용
+ });
+ // AccessTokenGuard 전역 Guard로 설정
+ const authService = app.get(AuthService);
+ app.useGlobalGuards(new AccessTokenGuard(authService));
+
+ app.useGlobalPipes(
+ new ValidationPipe({
+ transform: true, // 요청에서 넘어온 자료들의 형변환을 자동으로 해줌
+ transformOptions: {
+ enableImplicitConversion: true, // true로 설정하면, 자동 형변환을 허용함
+ },
+ whitelist: true, // 데코레이터가 없는 속성들은 제거해줌
+ forbidNonWhitelisted: true, // 데코레이터가 없는 속성이 있으면 요청 자체를 막아버림
+ }),
+ );
+ app.useWebSocketAdapter(new WsAdapter(app));
+
+ const port = process.env.PORT || 3000; // 환경 변수에서 포트를 가져오거나 기본값으로 3000 사용
+ await app.listen(port);
+ console.log(`Application is running on: ${await app.getUrl()}`);
+}
+
+bootstrap();
diff --git a/server/src/shared-checklists/dto/create-shared-checklist.dto.ts b/server/src/shared-checklists/dto/create-shared-checklist.dto.ts
new file mode 100644
index 00000000..4044bdbc
--- /dev/null
+++ b/server/src/shared-checklists/dto/create-shared-checklist.dto.ts
@@ -0,0 +1,21 @@
+import { PickType } from '@nestjs/mapped-types';
+import { IsNotEmpty, IsString, IsUUID } from 'class-validator';
+import { SharedChecklistModel } from '../entities/shared-checklist.entity';
+
+export class CreateSharedChecklistDto extends PickType(SharedChecklistModel, [
+ 'title',
+ 'sharedChecklistId',
+ 'items',
+]) {
+ // @IsNumber({}, { each: true })
+ // editorsId: number[] = [];
+ @IsString()
+ @IsNotEmpty()
+ title: string;
+
+ @IsUUID()
+ sharedChecklistId: string;
+
+ @IsNotEmpty()
+ items: any;
+}
diff --git a/server/src/shared-checklists/dto/update-shared-checklist.dto.ts b/server/src/shared-checklists/dto/update-shared-checklist.dto.ts
new file mode 100644
index 00000000..2218a230
--- /dev/null
+++ b/server/src/shared-checklists/dto/update-shared-checklist.dto.ts
@@ -0,0 +1,15 @@
+import { PartialType } from '@nestjs/mapped-types';
+import { SharedChecklistModel } from '../entities/shared-checklist.entity';
+import { IsNumber, IsOptional, IsString } from 'class-validator';
+
+export class UpdateSharedChecklistDto extends PartialType(
+ SharedChecklistModel,
+) {
+ @IsString()
+ @IsOptional()
+ title?: string;
+
+ @IsNumber({}, { each: true })
+ @IsOptional()
+ editorsId?: number[] = [];
+}
diff --git a/server/src/shared-checklists/entities/shared-checklist-item.entity.ts b/server/src/shared-checklists/entities/shared-checklist-item.entity.ts
new file mode 100644
index 00000000..3228eabb
--- /dev/null
+++ b/server/src/shared-checklists/entities/shared-checklist-item.entity.ts
@@ -0,0 +1,18 @@
+import { BaseModel } from 'src/common/entity/base.entity';
+import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
+import { SharedChecklistModel } from './shared-checklist.entity';
+
+@Entity()
+export class SharedChecklistItemModel extends BaseModel {
+ @PrimaryGeneratedColumn()
+ itemId: number;
+
+ @ManyToOne(
+ () => SharedChecklistModel,
+ (sharedChecklist) => sharedChecklist.items,
+ )
+ sharedChecklist: SharedChecklistModel;
+
+ @Column({ type: 'json' })
+ messages: any[];
+}
diff --git a/server/src/shared-checklists/entities/shared-checklist.entity.ts b/server/src/shared-checklists/entities/shared-checklist.entity.ts
new file mode 100644
index 00000000..6833ac9a
--- /dev/null
+++ b/server/src/shared-checklists/entities/shared-checklist.entity.ts
@@ -0,0 +1,25 @@
+import {
+ Entity,
+ JoinTable,
+ ManyToMany,
+ OneToMany,
+ PrimaryColumn,
+} from 'typeorm';
+import { ChecklistModel } from '../../common/entity/checklist.entity';
+import { UserModel } from '../../users/entities/user.entity';
+import { SharedChecklistItemModel } from './shared-checklist-item.entity';
+
+@Entity()
+export class SharedChecklistModel extends ChecklistModel {
+ @PrimaryColumn({ type: 'uuid' })
+ sharedChecklistId: string;
+
+ @ManyToMany(() => UserModel, (user) => user.sharedChecklists, {
+ nullable: false,
+ })
+ @JoinTable()
+ editors: UserModel[];
+
+ @OneToMany(() => SharedChecklistItemModel, (item) => item.sharedChecklist)
+ items: SharedChecklistItemModel[];
+}
diff --git a/server/src/shared-checklists/shared-checklists.controller.ts b/server/src/shared-checklists/shared-checklists.controller.ts
new file mode 100644
index 00000000..297b81ce
--- /dev/null
+++ b/server/src/shared-checklists/shared-checklists.controller.ts
@@ -0,0 +1,85 @@
+import {
+ Body,
+ Controller,
+ Delete,
+ Get,
+ Param,
+ Post,
+ Query,
+} from '@nestjs/common';
+import { UserId } from 'src/users/decorator/userId.decorator';
+import { CreateSharedChecklistDto } from './dto/create-shared-checklist.dto';
+import { UpdateSharedChecklistDto } from './dto/update-shared-checklist.dto';
+import { SharedChecklistsService } from './shared-checklists.service';
+
+@Controller('shared-checklists')
+export class SharedChecklistsController {
+ constructor(private readonly checklistsService: SharedChecklistsService) {}
+
+ /**
+ * @description userId와 title을 통해 해당 folder에 새로운 checklist를 생성합니다.
+ * @param {CreateSharedChecklistDto} createSharedChecklistDto
+ * @returns {Promise}
+ */
+ @Post()
+ postSharedChecklist(
+ @UserId() userId: number,
+ @Body() createSharedChecklistDto: CreateSharedChecklistDto,
+ ) {
+ return this.checklistsService.createSharedChecklistAndItems(
+ userId,
+ createSharedChecklistDto,
+ );
+ }
+
+ /**
+ * @description 모든 checklist를 조회합니다.
+ * @returns {Promise}
+ */
+ @Get()
+ getAllSharedChecklists(@UserId() userId: number) {
+ return this.checklistsService.findAllSharedChecklists(userId);
+ }
+
+ /**
+ * @description checklistId를 통해 해당 checklist를 조회합니다.
+ * @param {string} cid
+ * @returns {Promise}
+ */
+ @Get(':checklistId')
+ getSharedChecklist(
+ @Param('checklistId') cid: string,
+ @UserId() userId: number,
+ @Query('date') date?: string, // 새로운 쿼리 파라미터 추가
+ ) {
+ return this.checklistsService.findSharedChecklistAndItemsById(
+ cid,
+ userId,
+ date,
+ );
+ }
+
+ /**
+ * @description checklistId를 통해 해당 checklist의 title을 수정합니다.
+ * @param {string} cid
+ * @param {UpdateSharedChecklistDto} updateChecklistDto
+ * @returns {Promise}
+ */
+ @Post(':checklistId/editors')
+ updateSharedChecklist(
+ @Param('checklistId') cid: string,
+ @UserId() userId: number,
+ ) {
+ return this.checklistsService.addEditor(cid, userId);
+ }
+
+ /**
+ * @description checklistId를 통해 해당 checklist를 삭제합니다.
+ * @param {string} cid
+ * @returns {Promise}
+ */
+ @Delete(':checklistId')
+ deleteChecklist(@Param('checklistId') cid: string, @UserId() userId: number) {
+ return this.checklistsService.removeEditor(cid, userId);
+ }
+}
diff --git a/server/src/shared-checklists/shared-checklists.gateway.ts b/server/src/shared-checklists/shared-checklists.gateway.ts
new file mode 100644
index 00000000..b64363f3
--- /dev/null
+++ b/server/src/shared-checklists/shared-checklists.gateway.ts
@@ -0,0 +1,341 @@
+import { Inject } from '@nestjs/common';
+import {
+ ConnectedSocket,
+ MessageBody,
+ OnGatewayConnection,
+ OnGatewayDisconnect,
+ SubscribeMessage,
+ WebSocketGateway,
+ WebSocketServer,
+} from '@nestjs/websockets';
+import { RedisClientType } from 'redis';
+import { parse } from 'url';
+import { v1 as uuid } from 'uuid';
+import * as WebSocket from 'ws';
+import { SharedChecklistsService } from './shared-checklists.service';
+
+/**
+ * 웹소켓 통신을 통해 클라이언트들의 체크리스트 공유를 관리하는 게이트웨이.
+ */
+@WebSocketGateway({ path: '/share-checklist' })
+export class SharedChecklistsGateway
+ implements OnGatewayConnection, OnGatewayDisconnect
+{
+ constructor(
+ private readonly sharedChecklistsService: SharedChecklistsService,
+ @Inject('REDIS_CLIENT')
+ private readonly redisClient: RedisClientType,
+ @Inject('REDIS_PUB_CLIENT')
+ private readonly redisPublisher: RedisClientType,
+ @Inject('REDIS_SUB_CLIENT')
+ private readonly redisSubscriber: RedisClientType,
+ ) {
+ // 서버 식별자 생성
+ this.serverUuid = uuid();
+ // Redis 구독 초기화
+ this.initializeRedisSubscriber();
+ }
+ @WebSocketServer() server: WebSocket.Server;
+
+ // 각 checklist ID별로 연결된 클라이언트들을 추적하기 위한 맵
+ private clients: Map> = new Map();
+ // 서버 식별자
+ private serverUuid: string;
+
+ /**
+ * 클라이언트가 연결을 시도할 때 호출되는 메서드.
+ * 연결된 클라이언트에 sharedChecklistId를 할당하고 관리한다.
+ * @param client 연결된 클라이언트의 웹소켓 객체
+ */
+ async handleConnection(@ConnectedSocket() client: WebSocket, ...args: any[]) {
+ const sharedChecklistId = this.getSharedChecklistId(args[0]);
+ if (!sharedChecklistId)
+ return { event: 'error', data: 'No sharedChecklistId provided' };
+ client['sharedChecklistId'] = sharedChecklistId;
+ // 고유 식별자 생성
+ const clientId = uuid();
+
+ // WebSocket 객체에 식별자 첨부
+ client['id'] = clientId;
+
+ this.addClientToMap(client, sharedChecklistId);
+ const count = await this.updateRedisCount(sharedChecklistId, true);
+
+ const logMessage = `CONNECT ::: CLIENT:${clientId} CHECKLIST:${sharedChecklistId} Count: ${count}`;
+ console.log(logMessage);
+ this.redisPublisher.publish('wsLog', logMessage);
+
+ await this.sendHistoryToClient(client, sharedChecklistId);
+
+ console.log(``);
+ }
+
+ /**
+ * 클라이언트 연결이 해제될 때 호출되는 메서드.
+ * 해당 클라이언트를 관리 목록에서 제거한다.
+ * @param client 연결 해제된 클라이언트의 웹소켓 객체
+ */
+ async handleDisconnect(@ConnectedSocket() client: WebSocket) {
+ const sharedChecklistId = client['sharedChecklistId'];
+ const clientId = client['id'];
+ if (!(sharedChecklistId && this.clients.has(sharedChecklistId))) return;
+
+ this.removeClientFromMap(client, sharedChecklistId);
+ const count = await this.updateRedisCount(sharedChecklistId, false);
+
+ // console.log(
+ // `DISCONNECT ::: CLIENT:${clientId} CHECKLIST:${sharedChecklistId} Count: ${count}`,
+ // );
+
+ const logMessage = `DISCONNECT ::: CLIENT:${clientId} CHECKLIST:${sharedChecklistId} Count: ${count}`;
+ console.log(logMessage);
+ this.redisPublisher.publish('wsLog', logMessage);
+ console.log(``);
+
+ if (count === 0) {
+ await this.handleNoClientsConnected(sharedChecklistId);
+ }
+ }
+
+ /**
+ * 더 이상 연결된 클라이언트가 없을 때 처리하는 메서드이다.
+ * 레디스의 sharedChecklistHistory를 postgres DB에 저장 후, Redis에서 해당 키를 삭제한다.
+ * @param sharedChecklistId 공유 체크리스트의 식별자
+ */
+ private async handleNoClientsConnected(sharedChecklistId: string) {
+ const redisArrayKey = `sharedChecklistHistory:${sharedChecklistId}`;
+ const history = await this.redisClient.lRange(redisArrayKey, 0, -1);
+ const historyArray = history.map((item) => JSON.parse(item));
+ const flattenedArray = historyArray.flat();
+ if (history.length > 0) {
+ await this.saveToDatabase(sharedChecklistId, flattenedArray);
+ await this.redisClient.del(redisArrayKey);
+ }
+ }
+ /**
+ * 요청으로부터 sharedChecklistId를 추출하는 메서드이다.
+ * 클라이언트의 요청 URL에서 sharedChecklistId를 파싱하여 반환한다.
+ * @param request 클라이언트의 요청 객체
+ * @returns 추출된 sharedChecklistId
+ */
+ private getSharedChecklistId(request: { url: string }) {
+ const { query } = parse(request.url, true);
+ const sharedChecklistId = query.cid as string;
+ return sharedChecklistId;
+ }
+
+ /**
+ * 클라이언트를 로컬 관리 맵에 추가하는 메서드이다.
+ * sharedChecklistId에 해당하는 클라이언트 집합이 없으면 새로 생성하고, 클라이언트를 추가한다.
+ * @param client 추가할 클라이언트의 웹소켓 객체
+ * @param sharedChecklistId 공유 체크리스트의 식별자
+ */ private addClientToMap(client: WebSocket, sharedChecklistId: string) {
+ if (!this.clients.has(sharedChecklistId)) {
+ this.clients.set(sharedChecklistId, new Set());
+ }
+ this.clients.get(sharedChecklistId)?.add(client);
+ }
+
+ /**
+ * 클라이언트를 로컬 관리 맵에서 제거하는 메서드이다.
+ * sharedChecklistId에 해당하는 클라이언트 집합에서 클라이언트를 제거한다.
+ * 해당 집합의 크기가 0이 되면, 집합 자체를 맵에서 제거한다.
+ * @param client 제거할 클라이언트의 웹소켓 객체
+ * @param sharedChecklistId 공유 체크리스트의 식별자
+ */
+ private removeClientFromMap(client: WebSocket, sharedChecklistId: string) {
+ const clientsSet = this.clients.get(sharedChecklistId);
+ clientsSet?.delete(client);
+ if (clientsSet?.size === 0) {
+ this.clients.delete(sharedChecklistId);
+ }
+ }
+
+ /**
+ * Redis에 sharedChecklistId 클라이언트 수를 업데이트하는 메서드이다.
+ * 클라이언트가 연결되면 카운트를 증가시키고, 연결이 해제되면 감소시킨다.
+ * @param sharedChecklistId 공유 체크리스트의 식별자
+ * @param isConnecting 클라이언트가 연결 중인지 여부 (연결 중이면 true, 연결 해제 중이면 false)
+ * @returns 업데이트된 클라이언트 수
+ */
+ private async updateRedisCount(
+ sharedChecklistId: string,
+ isConnecting: boolean,
+ ) {
+ const redisCountKey = `sharedChecklistCount:${sharedChecklistId}`;
+ if (isConnecting) {
+ await this.redisClient.INCR(redisCountKey);
+ } else {
+ await this.redisClient.DECR(redisCountKey);
+ }
+ return parseInt(await this.redisClient.GET(redisCountKey), 10);
+ }
+
+ /**
+ * sharedChecklistId 클라이언트에 누적 데이터값을 전송하는 메서드이다.
+ * sharedChecklistId에 해당하는 누적 데이터값을 Redis에서 조회하여 클라이언트에 전송한다.
+ * @param client 이력을 전송할 클라이언트의 웹소켓 객체
+ * @param sharedChecklistId 공유 체크리스트의 식별자
+ */
+ private async sendHistoryToClient(
+ client: WebSocket,
+ sharedChecklistId: string,
+ ) {
+ const redisArrayKey = `sharedChecklistHistory:${sharedChecklistId}`;
+ const history = await this.redisClient.lRange(redisArrayKey, 0, -1);
+ const historyArray = history.map((item) => JSON.parse(item));
+ const flattenedArray = historyArray.flat();
+
+ this.sendToClient(client, 'history', flattenedArray);
+ }
+
+ /**
+ * Redis 구독을 초기화하는 메서드이다.
+ * 'sharedChecklist' 채널로부터 메시지를 받으면 해당 메시지를 로컬 클라이언트들에게 브로드캐스트한다.
+ */
+ private initializeRedisSubscriber() {
+ this.redisSubscriber.subscribe('sharedChecklist', (message) => {
+ const { serverUuid, sharedChecklistId, event, data } =
+ JSON.parse(message);
+ if (serverUuid !== this.serverUuid) {
+ this.broadcastToLocal(sharedChecklistId, event, data);
+ }
+ });
+ }
+ /**
+ * 특정 sharedChecklistId를 가진 클라이언트들에게 이벤트와 데이터를 브로드캐스트하는 메서드이다.
+ * 메시지를 보낸 클라이언트는 브로드캐스트에서 제외한다.
+ * @param sharedChecklistId 브로드캐스트 대상의 checklist ID
+ * @param event 브로드캐스트할 이벤트 이름
+ * @param data 전송할 데이터
+ * @param excludeClient 브로드캐스트에서 제외할 클라이언트
+ */
+ private broadcastToLocal(
+ sharedChecklistId: string,
+ event: string,
+ data: any,
+ excludeClient?: WebSocket,
+ ) {
+ const clients = this.clients.get(sharedChecklistId);
+ if (clients) {
+ clients.forEach((client) => {
+ if (client !== excludeClient && client.readyState === WebSocket.OPEN) {
+ this.sendToClient(client, event, data);
+ }
+ });
+ }
+ }
+
+ /**
+ * 'send' 이벤트에 대한 요청을 처리하고, 해당 sharedChecklistId를 가진 다른 클라이언트들에게 'listen' 이벤트를 브로드캐스트하는 메서드이다.
+ * 또한, Redis 채널에 게시하여 다른 서버에도 'listen' 이벤트를 브로드캐스트한다.
+ * @param client 메시지를 보낸 클라이언트의 웹소켓 객체
+ * @param data 클라이언트로부터 받은 데이터
+ * @returns 이벤트 처리 결과를 나타내는 객체
+ */
+ @SubscribeMessage('send')
+ async handleSendChecklist(
+ @ConnectedSocket() client: WebSocket,
+ @MessageBody() data: string,
+ sharedChecklistId: string = client['sharedChecklistId'],
+ ) {
+ this.broadcastToLocal(sharedChecklistId, 'listen', data, client);
+ const serverUuid = this.serverUuid;
+ const message = JSON.stringify({
+ serverUuid,
+ sharedChecklistId,
+ event: 'listen',
+ data,
+ });
+
+ const clientId = client['id'];
+ // console.log(
+ // `POST send ::: CLIENT:${clientId} CHECKLIST:${sharedChecklistId}`,
+ // );
+ // console.log(`data: ${JSON.stringify(data)}`);
+ const logMessage = `POST send ::: CLIENT:${clientId} CHECKLIST:${sharedChecklistId}`;
+ console.log(logMessage);
+ this.redisPublisher.publish('wsLog', logMessage);
+ console.log(`data: ${JSON.stringify(data)}`);
+ this.redisPublisher.publish('wsLog', JSON.stringify(data));
+ console.log(``);
+ this.redisPublisher.publish('sharedChecklist', message);
+ const redisArrayKey = `sharedChecklistHistory:${sharedChecklistId}`;
+ const dataToJson = JSON.stringify(data);
+ this.redisClient.rPush(redisArrayKey, dataToJson);
+ }
+
+ @SubscribeMessage('editing')
+ async handleEditingChecklist(
+ @ConnectedSocket() client: WebSocket,
+ @MessageBody() data: string,
+ sharedChecklistId: string = client['sharedChecklistId'],
+ ) {
+ this.broadcastToLocal(sharedChecklistId, 'editing', data, client);
+ const serverUuid = this.serverUuid;
+ const message = JSON.stringify({
+ serverUuid,
+ sharedChecklistId,
+ event: 'editing',
+ data,
+ });
+ this.redisPublisher.publish('sharedChecklist', message);
+ // console.log(`POST editing ::: CHECKLIST:${sharedChecklistId}`);
+ // console.log(`data: ${JSON.stringify(data)}`);
+ const logMessage = `POST editing ::: CHECKLIST:${sharedChecklistId}`;
+ console.log(logMessage);
+ this.redisPublisher.publish('wsLog', logMessage);
+ console.log(`data: ${JSON.stringify(data)}`);
+ console.log(``);
+ }
+ /**
+ * 특정 클라이언트에 이벤트와 데이터를 전송한다.
+ * @param client 데이터를 전송할 클라이언트의 웹소켓 객체
+ * @param event 전송할 이벤트 이름
+ * @param data 전송할 데이터
+ */
+ private sendToClient(
+ client: WebSocket,
+ event: string,
+ data: string[] | string,
+ ) {
+ // console.log(
+ // `GET ${event} ::: CLIENT:${client['id']} CHECKLIST:${client['sharedChecklistId']}`,
+ // );
+ // console.log(`data: ${JSON.stringify(data)}`);
+ const logMessage = `GET ${event} ::: CLIENT:${client['id']} CHECKLIST:${client['sharedChecklistId']}`;
+ console.log(logMessage);
+ this.redisPublisher.publish('wsLog', logMessage);
+ console.log(`data: ${JSON.stringify(data)}`);
+ this.redisPublisher.publish('wsLog', JSON.stringify(data));
+ console.log(``);
+
+ client.send(JSON.stringify({ event, data }));
+ }
+
+ /**
+ * sharedChecklistId에 해당하는 데이터를 데이터베이스에 저장하는 메서드이다.
+ * 데이터가 누적되면 sharedChecklistsService를 통해 데이터베이스에 저장한다.
+ * @param sharedChecklistId 공유 체크리스트의 식별자
+ * @param dataForThisChecklist 저장할 데이터 목록
+ */
+ private async saveToDatabase(sharedChecklistId: string, history: string[]) {
+ const now = new Date();
+ const result = await this.sharedChecklistsService.createSharedChecklistItem(
+ history,
+ sharedChecklistId,
+ now,
+ );
+ // console.log(
+ // `saveToDatabase CHECKLIST: ${sharedChecklistId}: ${JSON.stringify(
+ // result,
+ // )}`,
+ // );
+ const logMessage = `saveToDatabase CHECKLIST: ${sharedChecklistId}}`;
+ console.log(logMessage);
+ this.redisPublisher.publish('wsLog', logMessage);
+ console.log(`data: ${JSON.stringify(result)}`);
+ this.redisPublisher.publish('wsLog', JSON.stringify(result));
+ console.log(``);
+ }
+}
diff --git a/server/src/shared-checklists/shared-checklists.module.ts b/server/src/shared-checklists/shared-checklists.module.ts
new file mode 100644
index 00000000..61e78db8
--- /dev/null
+++ b/server/src/shared-checklists/shared-checklists.module.ts
@@ -0,0 +1,20 @@
+import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+import { FoldersModule } from '../folders/folders.module';
+import { UsersModule } from '../users/users.module';
+import { SharedChecklistItemModel } from './entities/shared-checklist-item.entity';
+import { SharedChecklistModel } from './entities/shared-checklist.entity';
+import { SharedChecklistsController } from './shared-checklists.controller';
+import { SharedChecklistsGateway } from './shared-checklists.gateway';
+import { SharedChecklistsService } from './shared-checklists.service';
+
+@Module({
+ imports: [
+ TypeOrmModule.forFeature([SharedChecklistModel, SharedChecklistItemModel]),
+ FoldersModule,
+ UsersModule,
+ ],
+ controllers: [SharedChecklistsController],
+ providers: [SharedChecklistsService, SharedChecklistsGateway],
+})
+export class SharedChecklistsModule {}
diff --git a/server/src/shared-checklists/shared-checklists.service.ts b/server/src/shared-checklists/shared-checklists.service.ts
new file mode 100644
index 00000000..9b692b34
--- /dev/null
+++ b/server/src/shared-checklists/shared-checklists.service.ts
@@ -0,0 +1,237 @@
+import { BadRequestException, Injectable } from '@nestjs/common';
+import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
+import { UsersService } from 'src/users/users.service';
+import { EntityManager, In, MoreThan, Repository } from 'typeorm';
+import { CreateSharedChecklistDto } from './dto/create-shared-checklist.dto';
+import { SharedChecklistItemModel } from './entities/shared-checklist-item.entity';
+import { SharedChecklistModel } from './entities/shared-checklist.entity';
+
+@Injectable()
+export class SharedChecklistsService {
+ constructor(
+ @InjectRepository(SharedChecklistModel)
+ private readonly SharedChecklistsrepository: Repository,
+
+ @InjectRepository(SharedChecklistItemModel)
+ private readonly SharedChecklistItemsrepository: Repository,
+
+ @InjectEntityManager()
+ private entityManager: EntityManager,
+
+ private readonly usersService: UsersService,
+ ) {}
+ /**
+ * 사용자 ID와 공유 체크리스트 데이터를 받아 새로운 공유 체크리스트를 생성한다.
+ * @param userId 사용자 식별자
+ * @param dto 공유 체크리스트 생성에 필요한 데이터 전송 객체
+ * @returns 생성된 공유 체크리스트 객체
+ */
+ async createSharedChecklist(userId: number, dto: CreateSharedChecklistDto) {
+ // 사용자가 존재하는지 확인
+ const user = await this.usersService.findUserById(userId);
+ // 중복된 sharedChecklistId가 있는지 확인
+ const checklistExists = await this.SharedChecklistsrepository.exist({
+ where: {
+ sharedChecklistId: dto.sharedChecklistId,
+ },
+ });
+ if (checklistExists) {
+ throw new BadRequestException('이미 존재하는 체크리스트 아이디입니다.');
+ }
+ // 새 Checklist 생성
+ const newChecklist = this.SharedChecklistsrepository.create({
+ title: dto.title,
+ sharedChecklistId: dto.sharedChecklistId,
+ editors: [{ userId }],
+ });
+ // Checklist 저장
+ return this.SharedChecklistsrepository.save(newChecklist);
+ }
+
+ /**
+ * 체크리스트 아이템 데이터와 체크리스트 ID를 받아 새로운 체크리스트 아이템을 생성한다.
+ * @param items 체크리스트 아이템의 메시지 배열
+ * @param checklistId 체크리스트 식별자
+ * @param now 전달되는 현재 시간(옵션)
+ * @returns 생성된 체크리스트 아이템 객체
+ */
+ async createSharedChecklistItem(
+ items: string[],
+ checklistId: string,
+ now?: Date,
+ ) {
+ // 새 ChecklistItem 생성
+ const checklistItemData = {
+ messages: items,
+ sharedChecklist: { sharedChecklistId: checklistId },
+ };
+
+ if (now) {
+ checklistItemData['createdAt'] = now;
+ checklistItemData['updatedAt'] = now;
+ }
+
+ const newChecklistItem =
+ this.SharedChecklistItemsrepository.create(checklistItemData);
+
+ return this.SharedChecklistItemsrepository.save(newChecklistItem);
+ }
+
+ /**
+ * 사용자 ID와 공유 체크리스트 데이터를 받아 새로운 공유 체크리스트와 체크리스트 아이템을 함께 생성한다.
+ * @param userId 사용자 식별자
+ * @param dto 공유 체크리스트 생성에 필요한 데이터 전송 객체
+ * @returns 생성된 공유 체크리스트와 체크리스트 아이템 객체
+ */
+ async createSharedChecklistAndItems(
+ userId: number,
+ dto: CreateSharedChecklistDto,
+ ) {
+ const sharedChecklist = await this.createSharedChecklist(userId, dto);
+ const items = await this.createSharedChecklistItem(
+ dto.items,
+ sharedChecklist.sharedChecklistId,
+ );
+ return { sharedChecklist, items };
+ }
+
+ /**
+ * 사용자 ID를 기반으로 모든 공유 체크리스트를 조회한다.
+ * @param userId 사용자 식별자
+ * @returns 해당 사용자의 모든 공유 체크리스트 배열
+ */
+ async findAllSharedChecklists(userId: number) {
+ const checklistIdsArray =
+ await this.findAllSharedChecklistIdsByUserId(userId);
+ const checklists = await this.SharedChecklistsrepository.find({
+ where: {
+ sharedChecklistId: In(checklistIdsArray),
+ },
+ relations: ['editors'],
+ });
+
+ return checklists;
+ }
+
+ /**
+ * 공유 체크리스트 ID와 사용자 ID를 받아 해당 체크리스트와 체크리스트 아이템을 조회한다.
+ * @param sharedChecklistId 공유 체크리스트 식별자
+ * @param userId 사용자 식별자
+ * @param date 특정 날짜 이후의 체크리스트 아이템을 필터링하는 날짜 문자열 (선택적)
+ * @returns 조회된 공유 체크리스트와 체크리스트 아이템 객체
+ */
+ async findSharedChecklistAndItemsById(
+ sharedChecklistId: string,
+ userId: number,
+ date: string,
+ ) {
+ const sharedChecklist =
+ await this.findSharedChecklistById(sharedChecklistId);
+
+ if (!sharedChecklist.editors.some((editor) => editor.userId === userId)) {
+ throw new BadRequestException('권한이 없습니다.');
+ }
+ delete sharedChecklist.editors;
+
+ const items = await this.findSharedChecklistItemsById(
+ sharedChecklistId,
+ date,
+ );
+ return { sharedChecklist, items };
+ }
+
+ /**
+ * 공유 체크리스트 ID를 기반으로 공유 체크리스트를 조회한다.
+ * @param sharedChecklistId 공유 체크리스트 식별자
+ * @returns 조회된 공유 체크리스트 객체
+ */
+ async findSharedChecklistById(sharedChecklistId: string) {
+ const sharedChecklist = await this.SharedChecklistsrepository.findOne({
+ where: { sharedChecklistId },
+ relations: ['editors'],
+ });
+ if (!sharedChecklist) {
+ throw new BadRequestException('존재하지 않는 체크리스트입니다.');
+ }
+
+ return sharedChecklist;
+ }
+
+ /**
+ * 공유 체크리스트 ID를 기반으로 해당 체크리스트의 모든 아이템을 조회한다.
+ * @param sharedChecklistId 공유 체크리스트 식별자
+ * @param date 선택적 날짜 필터링 (이 날짜 이후의 아이템만 조회)
+ * @returns 조회된 체크리스트 아이템 배열
+ */
+ async findSharedChecklistItemsById(sharedChecklistId: string, date?: string) {
+ const queryOptions = {
+ where: { sharedChecklist: { sharedChecklistId } },
+ };
+ if (date) {
+ const dateObj = new Date(date);
+ if (!isNaN(dateObj.getTime())) {
+ queryOptions.where['createdAt'] = MoreThan(dateObj);
+ }
+ }
+
+ const checklistItems =
+ await this.SharedChecklistItemsrepository.find(queryOptions);
+
+ if (!checklistItems) {
+ throw new BadRequestException('존재하지 않는 체크리스트입니다.');
+ }
+
+ return checklistItems;
+ }
+
+ /**
+ * 사용자 ID를 기반으로 해당 사용자가 편집자로 있는 모든 공유 체크리스트 ID를 조회한다.
+ * @param userId 사용자 식별자
+ * @returns 해당 사용자가 편집자로 있는 공유 체크리스트 ID 배열
+ */
+ async findAllSharedChecklistIdsByUserId(userId: number) {
+ const checklistIdObjects = await this.entityManager.query(
+ `SELECT "sharedChecklistModelSharedChecklistId" FROM shared_checklist_model_editors_user_model WHERE "userModelUserId" = $1`,
+ [userId],
+ );
+ return checklistIdObjects.map(
+ (obj) => obj.sharedChecklistModelSharedChecklistId,
+ );
+ }
+
+ /**
+ * 공유 체크리스트 ID와 사용자 ID를 기반으로 새로운 에디터를 해당 체크리스트에 추가한다.
+ * @param cid 공유 체크리스트 식별자
+ * @param userId 추가할 사용자 식별자
+ * @returns 추가 작업에 대한 메시지
+ */
+ async addEditor(cid: string, userId: number) {
+ const checklist = await this.findSharedChecklistById(cid);
+ const editorExists = checklist.editors.some(
+ (editor) => editor.userId === userId,
+ );
+ if (editorExists) {
+ throw new BadRequestException('이미 공유된 체크리스트입니다.');
+ }
+
+ const user = await this.usersService.findUserById(userId);
+ checklist.editors.push(user);
+ await this.SharedChecklistsrepository.save(checklist);
+ return { message: '추가되었습니다.' };
+ }
+
+ /**
+ * 공유 체크리스트 ID와 사용자 ID를 기반으로 해당 체크리스트에서 사용자를 제거한다.
+ * @param id 공유 체크리스트 식별자
+ * @param userId 제거할 사용자 식별자
+ * @returns 제거 작업에 대한 메시지
+ */
+ async removeEditor(id: string, userId: number) {
+ const checklist = await this.findSharedChecklistById(id);
+ checklist.editors = checklist.editors.filter(
+ (editor) => editor.userId !== userId,
+ );
+ await this.SharedChecklistsrepository.save(checklist);
+ return { message: '삭제되었습니다.' };
+ }
+}
diff --git a/server/src/users/decorator/userId.decorator.ts b/server/src/users/decorator/userId.decorator.ts
new file mode 100644
index 00000000..aaf1702c
--- /dev/null
+++ b/server/src/users/decorator/userId.decorator.ts
@@ -0,0 +1,21 @@
+import {
+ createParamDecorator,
+ ExecutionContext,
+ InternalServerErrorException,
+} from '@nestjs/common';
+
+/**
+ * @UserId 커스텀 데코레이터
+ * ExecutionContext로부터 HTTP 요청을 추출하고, 해당 요청에서 userId를 반환한다.
+ * 이 데코레이터는 컨트롤러의 핸들러 메소드에서 사용되며, 인증된 사용자의 식별자를 제공한다.
+ * 요청 객체에 사용자 정보가 없는 경우 InternalServerErrorException을 발생시킨다.
+ */
+export const UserId = createParamDecorator(
+ (data: unknown, ctx: ExecutionContext) => {
+ const request = ctx.switchToHttp().getRequest();
+ if (!request.userId) {
+ throw new InternalServerErrorException('사용자 정보가 없습니다.');
+ }
+ return request.userId;
+ },
+);
diff --git a/server/src/users/dto/create-user.dto.ts b/server/src/users/dto/create-user.dto.ts
new file mode 100644
index 00000000..47d2174e
--- /dev/null
+++ b/server/src/users/dto/create-user.dto.ts
@@ -0,0 +1,30 @@
+import {
+ IsEmail,
+ IsEnum,
+ IsNotEmpty,
+ IsOptional,
+ IsString,
+} from 'class-validator';
+import { ProviderType } from '../entities/user.entity';
+
+export class CreateUserDto {
+ @IsString()
+ @IsNotEmpty()
+ providerId: string;
+
+ @IsEnum(ProviderType)
+ @IsNotEmpty()
+ provider: ProviderType;
+
+ @IsEmail()
+ @IsNotEmpty()
+ email: string;
+
+ @IsString()
+ @IsNotEmpty()
+ fullName: string;
+
+ @IsString()
+ @IsOptional()
+ nickname?: string;
+}
diff --git a/server/src/users/dto/update-user.dto.ts b/server/src/users/dto/update-user.dto.ts
new file mode 100644
index 00000000..c2e39207
--- /dev/null
+++ b/server/src/users/dto/update-user.dto.ts
@@ -0,0 +1,8 @@
+import { PartialType, PickType } from '@nestjs/mapped-types';
+import { CreateUserDto } from './create-user.dto';
+class PartialCreateUserDto extends PickType(CreateUserDto, [
+ 'email',
+ 'fullName',
+]) {}
+
+export class UpdateUserDto extends PartialType(PartialCreateUserDto) {}
diff --git a/server/src/users/entities/user.entity.ts b/server/src/users/entities/user.entity.ts
new file mode 100644
index 00000000..b4d43da2
--- /dev/null
+++ b/server/src/users/entities/user.entity.ts
@@ -0,0 +1,52 @@
+import { BaseModel } from 'src/common/entity/base.entity';
+import {
+ Column,
+ Entity,
+ ManyToMany,
+ OneToMany,
+ PrimaryGeneratedColumn,
+} from 'typeorm';
+import { FolderModel } from '../../folders/entities/folder.entity';
+import { PrivateChecklistModel } from '../../folders/private-checklists/entities/private-checklist.entity';
+import { SharedChecklistModel } from '../../shared-checklists/entities/shared-checklist.entity';
+
+export enum ProviderType {
+ APPLE = 'APPLE',
+ GOOGLE = 'GOOGLE',
+}
+@Entity()
+export class UserModel extends BaseModel {
+ @PrimaryGeneratedColumn()
+ userId: number;
+
+ @Column({ unique: true })
+ email: string;
+
+ @Column()
+ // @Generated('uuid') // 임시로 uuid를 생성해줌(원래는 provider의 고유 id를 받아와야함)
+ providerId: string;
+
+ @Column({
+ type: 'enum',
+ enum: ProviderType,
+ })
+ provider: ProviderType;
+
+ @Column()
+ fullName: string;
+
+ @Column()
+ nickname: string;
+
+ @Column({ default: 'testimagelink' })
+ profileImage: string;
+
+ @OneToMany(() => FolderModel, (folder) => folder.owner)
+ folders: FolderModel[];
+
+ @OneToMany(() => PrivateChecklistModel, (checklist) => checklist.editor)
+ privateChecklists: PrivateChecklistModel[];
+
+ @ManyToMany(() => SharedChecklistModel, (checklist) => checklist.editors)
+ sharedChecklists: SharedChecklistModel[];
+}
diff --git a/server/src/users/users.controller.spec.ts b/server/src/users/users.controller.spec.ts
new file mode 100644
index 00000000..5dca29af
--- /dev/null
+++ b/server/src/users/users.controller.spec.ts
@@ -0,0 +1,24 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { UsersController } from './users.controller';
+import { UsersService } from './users.service';
+import { TestCommonModule } from 'test/test-common.module';
+import { TypeOrmModule } from '@nestjs/typeorm';
+import { UserModel } from './entities/user.entity';
+
+describe('UsersController', () => {
+ let controller: UsersController;
+
+ beforeEach(async () => {
+ const module: TestingModule = await Test.createTestingModule({
+ imports: [TestCommonModule, TypeOrmModule.forFeature([UserModel])],
+ controllers: [UsersController],
+ providers: [UsersService],
+ }).compile();
+
+ controller = module.get(UsersController);
+ });
+
+ it('should be defined', () => {
+ expect(controller).toBeDefined();
+ });
+});
diff --git a/server/src/users/users.controller.ts b/server/src/users/users.controller.ts
new file mode 100644
index 00000000..a9e7e085
--- /dev/null
+++ b/server/src/users/users.controller.ts
@@ -0,0 +1,45 @@
+import {
+ Body,
+ Controller,
+ Delete,
+ Get,
+ Param,
+ Post,
+ Put,
+} from '@nestjs/common';
+import { CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { UsersService } from './users.service';
+
+@Controller('users')
+export class UsersController {
+ constructor(private readonly usersService: UsersService) {}
+
+ @Post()
+ postUser(@Body() createUserDto: CreateUserDto) {
+ return this.usersService.createUser(createUserDto);
+ }
+
+ @Get()
+ getUsers() {
+ return this.usersService.findAllUsers();
+ }
+
+ @Get(':userId')
+ getUser(@Param('userId') userId: number) {
+ return this.usersService.findUserById(userId);
+ }
+
+ @Put(':userId')
+ putUser(
+ @Param('userId') userId: number,
+ @Body() updateUserDto: UpdateUserDto,
+ ) {
+ return this.usersService.updateUser(userId, updateUserDto);
+ }
+
+ @Delete(':userId')
+ deleteUser(@Param('userId') userId: number) {
+ return this.usersService.removeUser(userId);
+ }
+}
diff --git a/server/src/users/users.module.ts b/server/src/users/users.module.ts
new file mode 100644
index 00000000..4590c47a
--- /dev/null
+++ b/server/src/users/users.module.ts
@@ -0,0 +1,13 @@
+import { Module } from '@nestjs/common';
+import { UsersService } from './users.service';
+import { UsersController } from './users.controller';
+import { TypeOrmModule } from '@nestjs/typeorm';
+import { UserModel } from './entities/user.entity';
+
+@Module({
+ imports: [TypeOrmModule.forFeature([UserModel])],
+ controllers: [UsersController],
+ providers: [UsersService],
+ exports: [UsersService],
+})
+export class UsersModule {}
diff --git a/server/src/users/users.service.spec.ts b/server/src/users/users.service.spec.ts
new file mode 100644
index 00000000..0922c98c
--- /dev/null
+++ b/server/src/users/users.service.spec.ts
@@ -0,0 +1,159 @@
+import { BadRequestException } from '@nestjs/common';
+import { Test, TestingModule } from '@nestjs/testing';
+import { getRepositoryToken } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+import { CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { ProviderType, UserModel } from './entities/user.entity';
+import { UsersService } from './users.service';
+
+type MockRepository = Partial, jest.Mock>>;
+
+describe('UsersService', () => {
+ let service: UsersService;
+ let mockUsersRepository: MockRepository;
+
+ beforeEach(async () => {
+ mockUsersRepository = {
+ create: jest.fn(),
+ save: jest.fn(),
+ findOne: jest.fn(),
+ find: jest.fn(),
+ remove: jest.fn(),
+ exist: jest.fn(),
+ };
+
+ const module: TestingModule = await Test.createTestingModule({
+ providers: [
+ UsersService,
+ {
+ provide: getRepositoryToken(UserModel),
+ useValue: mockUsersRepository,
+ },
+ ],
+ }).compile();
+
+ service = module.get(UsersService);
+ });
+
+ it('service.createUser(createUserDto) : 새로운 유저를 생성한다.', async () => {
+ const createUserDto: CreateUserDto = {
+ email: 'test@example.com',
+ fullName: 'TestUser',
+ nickname: 'TestUser',
+ providerId: '1234567890',
+ provider: ProviderType.APPLE, // Enum 멤버 사용
+ };
+ mockUsersRepository.exist.mockResolvedValue(false);
+ mockUsersRepository.create.mockReturnValue(createUserDto);
+ mockUsersRepository.save.mockResolvedValue({ userId: 1, ...createUserDto });
+
+ const result = await service.createUser(createUserDto);
+
+ expect(mockUsersRepository.exist).toHaveBeenCalledWith({
+ where: { email: createUserDto.email },
+ });
+ expect(mockUsersRepository.create).toHaveBeenCalledWith(createUserDto);
+ expect(mockUsersRepository.save).toHaveBeenCalledWith(createUserDto);
+ expect(result).toEqual({ userId: 1, ...createUserDto });
+ });
+
+ it('service.createUser(createUserDto) : 이미 존재하는 이메일일 경우 BadRequestException을 던진다.', async () => {
+ const createUserDto: CreateUserDto = {
+ email: 'test@example.com',
+ fullName: 'TestUser',
+ providerId: '1234567890',
+ provider: ProviderType.APPLE, // Enum 멤버 사용
+ };
+ mockUsersRepository.exist.mockResolvedValue(true);
+
+ await expect(service.createUser(createUserDto)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+
+ it('service.findAllUsers() : 모든 유저를 찾는다.', async () => {
+ const mockUsers = [
+ { userId: 1, email: 'test@example.com', nickname: 'TestUser' },
+ { userId: 2, email: 'test2@example.com', nickname: 'TestUser2' },
+ ];
+ mockUsersRepository.find.mockResolvedValue(mockUsers);
+
+ const result = await service.findAllUsers();
+
+ expect(mockUsersRepository.find).toHaveBeenCalled();
+ expect(result).toEqual(mockUsers);
+ });
+
+ it('service.findUserById(userId) : userId에 해당하는 유저를 찾는다.', async () => {
+ const user = { userId: 1, email: 'test@example.com', nickname: 'TestUser' };
+ mockUsersRepository.findOne.mockResolvedValue(user);
+
+ const result = await service.findUserById(1);
+
+ expect(mockUsersRepository.findOne).toHaveBeenCalledWith({
+ where: { userId: 1 },
+ });
+ expect(result).toEqual(user);
+ });
+
+ it('service.findUserById(userId) : 존재하지 않는 유저일 경우 BadRequestException을 던진다.', async () => {
+ mockUsersRepository.findOne.mockResolvedValue(null);
+
+ await expect(service.findUserById(1)).rejects.toThrow(BadRequestException);
+ });
+
+ it('service.updateUser(userId, updateUserDto) : userId에 해당하는 유저를 업데이트한다.', async () => {
+ const updateUserDto: UpdateUserDto = { fullName: 'UpdatedUser' };
+ const existingUser = {
+ userId: 1,
+ email: 'test@example.com',
+ fullName: 'TestUser',
+ nickname: 'TestUser',
+ };
+ mockUsersRepository.findOne.mockResolvedValue(existingUser);
+ mockUsersRepository.save.mockResolvedValue({
+ ...existingUser,
+ ...updateUserDto,
+ });
+
+ const result = await service.updateUser(1, updateUserDto);
+
+ expect(mockUsersRepository.findOne).toHaveBeenCalledWith({
+ where: { userId: 1 },
+ });
+ expect(mockUsersRepository.save).toHaveBeenCalledWith({
+ ...existingUser,
+ ...updateUserDto,
+ });
+ expect(result.fullName).toEqual('UpdatedUser');
+ });
+
+ it('service.updateUser(userId, updateUserDto) : 존재하지 않는 유저일 경우 BadRequestException을 던진다.', async () => {
+ const updateUserDto: UpdateUserDto = { fullName: 'UpdatedUser' };
+ mockUsersRepository.findOne.mockResolvedValue(null);
+
+ await expect(service.updateUser(1, updateUserDto)).rejects.toThrow(
+ BadRequestException,
+ );
+ });
+
+ it('service.removeUser(userId) : userId에 해당하는 유저를 삭제한다.', async () => {
+ const user = { userId: 1, email: 'test@example.com', nickname: 'TestUser' };
+ mockUsersRepository.findOne.mockResolvedValue(user);
+ mockUsersRepository.remove.mockResolvedValue(user);
+
+ const result = await service.removeUser(1);
+
+ expect(mockUsersRepository.findOne).toHaveBeenCalledWith({
+ where: { userId: 1 },
+ });
+ expect(mockUsersRepository.remove).toHaveBeenCalledWith(user);
+ expect(result).toEqual({ message: '삭제되었습니다.' });
+ });
+
+ it('service.removeUser(userId) : 존재하지 않는 유저일 경우 BadRequestException을 던진다.', async () => {
+ mockUsersRepository.findOne.mockResolvedValue(null);
+ await expect(service.removeUser(1)).rejects.toThrow(BadRequestException);
+ });
+});
diff --git a/server/src/users/users.service.ts b/server/src/users/users.service.ts
new file mode 100644
index 00000000..dfeb1877
--- /dev/null
+++ b/server/src/users/users.service.ts
@@ -0,0 +1,90 @@
+import { BadRequestException, Injectable } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { Repository } from 'typeorm';
+import { CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { ProviderType, UserModel } from './entities/user.entity';
+
+@Injectable()
+export class UsersService {
+ constructor(
+ @InjectRepository(UserModel)
+ private readonly usersRepository: Repository,
+ ) {}
+
+ async findUserByAppleId(appleId: string): Promise {
+ return await this.usersRepository.findOne({
+ where: { providerId: appleId, provider: ProviderType.APPLE },
+ });
+ }
+
+ async createAppleUser(dto: CreateUserDto): Promise {
+ if (!dto.nickname) {
+ dto.nickname = dto.fullName;
+ }
+ const userObj = this.usersRepository.create(dto);
+ const emailExists = await this.usersRepository.exist({
+ where: {
+ email: dto.email,
+ },
+ });
+ if (emailExists) {
+ throw new BadRequestException('이미 존재하는 이메일입니다.');
+ }
+ const newUser = await this.usersRepository.save(userObj);
+ return newUser;
+ }
+
+ async findAllUsers() {
+ const users = await this.usersRepository.find();
+ return users;
+ }
+
+ async findUserById(userId: number) {
+ const user = await this.usersRepository.findOne({ where: { userId } });
+ if (!user) {
+ throw new BadRequestException('존재하지 않는 유저입니다.');
+ }
+ return user;
+ }
+
+ async findUserByEmail(email: string) {
+ const user = await this.usersRepository.findOne({ where: { email } });
+ if (!user) {
+ throw new BadRequestException('존재하지 않는 유저입니다.');
+ }
+ return user;
+ }
+
+ async createUser(dto: CreateUserDto) {
+ if (!dto.nickname) {
+ dto.nickname = dto.fullName;
+ }
+ const userObject = this.usersRepository.create(dto);
+ const emailExists = await this.usersRepository.exist({
+ where: {
+ email: dto.email,
+ },
+ });
+ if (emailExists) {
+ throw new BadRequestException('이미 존재하는 이메일입니다.');
+ }
+ const newUser = await this.usersRepository.save(userObject);
+ return newUser;
+ }
+
+ async updateUser(userId: number, dto: UpdateUserDto) {
+ const user = await this.findUserById(userId);
+ const updatedUser = await this.usersRepository.save({
+ ...user,
+ ...dto,
+ });
+ return updatedUser;
+ }
+
+ async removeUser(userId: number) {
+ const user = await this.findUserById(userId);
+ await this.usersRepository.remove(user);
+ return { message: '삭제되었습니다.' };
+ }
+}
diff --git a/server/src/utils/winston.config.ts b/server/src/utils/winston.config.ts
new file mode 100644
index 00000000..bf5fd6cc
--- /dev/null
+++ b/server/src/utils/winston.config.ts
@@ -0,0 +1,44 @@
+import { utilities } from 'nest-winston';
+import * as winstonDaily from 'winston-daily-rotate-file';
+import * as winston from 'winston';
+
+const env = process.env.NODE_ENV;
+const logDir = __dirname + '/../../../logs'; // log 파일을 관리할 폴더
+
+const dailyOptions = (level: string) => {
+ return {
+ level,
+ datePattern: 'YYYY-MM-DD',
+ dirname: logDir + `/${level}`,
+ filename: `%DATE%.${level}.log`,
+ maxFiles: 30, //30일치 로그파일 저장
+ zippedArchive: true, // 로그가 쌓이면 압축하여 관리
+ };
+};
+
+// rfc5424를 따르는 winston만의 log level
+// error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
+export const winstonConfig = {
+ transports: [
+ new winston.transports.Console({
+ level: env === 'production' ? 'http' : 'silly',
+ // production 환경이라면 http, 개발환경이라면 모든 단계를 로그
+ format:
+ env === 'production'
+ ? // production 환경은 자원을 아끼기 위해 simple 포맷 사용
+ winston.format.simple()
+ : winston.format.combine(
+ winston.format.colorize(),
+ winston.format.timestamp(),
+ utilities.format.nestLike('OpenList', {
+ prettyPrint: true, // nest에서 제공하는 옵션. 로그 가독성을 높여줌
+ }),
+ ),
+ }),
+
+ // info, warn, error 로그는 파일로 관리
+ new winstonDaily(dailyOptions('info')),
+ new winstonDaily(dailyOptions('warn')),
+ new winstonDaily(dailyOptions('error')),
+ ],
+};
diff --git a/server/test/app.e2e-spec.ts b/server/test/app.e2e-spec.ts
new file mode 100644
index 00000000..50cda623
--- /dev/null
+++ b/server/test/app.e2e-spec.ts
@@ -0,0 +1,24 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { INestApplication } from '@nestjs/common';
+import * as request from 'supertest';
+import { AppModule } from './../src/app.module';
+
+describe('AppController (e2e)', () => {
+ let app: INestApplication;
+
+ beforeEach(async () => {
+ const moduleFixture: TestingModule = await Test.createTestingModule({
+ imports: [AppModule],
+ }).compile();
+
+ app = moduleFixture.createNestApplication();
+ await app.init();
+ });
+
+ it('/ (GET)', () => {
+ return request(app.getHttpServer())
+ .get('/')
+ .expect(200)
+ .expect('Hello World!');
+ });
+});
diff --git a/server/test/jest-e2e.json b/server/test/jest-e2e.json
new file mode 100644
index 00000000..e9d912f3
--- /dev/null
+++ b/server/test/jest-e2e.json
@@ -0,0 +1,9 @@
+{
+ "moduleFileExtensions": ["js", "json", "ts"],
+ "rootDir": ".",
+ "testEnvironment": "node",
+ "testRegex": ".e2e-spec.ts$",
+ "transform": {
+ "^.+\\.(t|j)s$": "ts-jest"
+ }
+}
diff --git a/server/test/test-common.module.ts b/server/test/test-common.module.ts
new file mode 100644
index 00000000..834a3948
--- /dev/null
+++ b/server/test/test-common.module.ts
@@ -0,0 +1,36 @@
+import { Module } from '@nestjs/common';
+import { ConfigModule } from '@nestjs/config';
+import { TypeOrmModule } from '@nestjs/typeorm';
+import { UserModel } from 'src/users/entities/user.entity';
+import { FolderModel } from '../src/folders/entities/folder.entity';
+import { FoldersModule } from '../src/folders/folders.module';
+import { PrivateChecklistModel } from '../src/folders/private-checklists/entities/private-checklist.entity';
+import { SharedChecklistModel } from '../src/shared-checklists/entities/shared-checklist.entity';
+import { UsersModule } from '../src/users/users.module';
+
+@Module({
+ imports: [
+ ConfigModule.forRoot({
+ envFilePath: '.env',
+ isGlobal: true,
+ }),
+ TypeOrmModule.forRoot({
+ type: 'postgres',
+ host: process.env['DB_HOST'],
+ port: parseInt(process.env['DB_PORT']),
+ username: process.env['DB_USERNAME'],
+ password: process.env['DB_PASSWORD'],
+ database: process.env['DB_DATABASE'],
+ entities: [
+ UserModel,
+ FolderModel,
+ PrivateChecklistModel,
+ SharedChecklistModel,
+ ],
+ synchronize: true,
+ }),
+ UsersModule,
+ FoldersModule,
+ ],
+})
+export class TestCommonModule {}
diff --git a/server/tsconfig.build.json b/server/tsconfig.build.json
new file mode 100644
index 00000000..64f86c6b
--- /dev/null
+++ b/server/tsconfig.build.json
@@ -0,0 +1,4 @@
+{
+ "extends": "./tsconfig.json",
+ "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
+}
diff --git a/server/tsconfig.json b/server/tsconfig.json
new file mode 100644
index 00000000..95f5641c
--- /dev/null
+++ b/server/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "declaration": true,
+ "removeComments": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "allowSyntheticDefaultImports": true,
+ "target": "ES2021",
+ "sourceMap": true,
+ "outDir": "./dist",
+ "baseUrl": "./",
+ "incremental": true,
+ "skipLibCheck": true,
+ "strictNullChecks": false,
+ "noImplicitAny": false,
+ "strictBindCallApply": false,
+ "forceConsistentCasingInFileNames": false,
+ "noFallthroughCasesInSwitch": false
+ }
+}
diff --git a/server/yarn.lock b/server/yarn.lock
new file mode 100644
index 00000000..cc60a93f
--- /dev/null
+++ b/server/yarn.lock
@@ -0,0 +1,5849 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@aashutoshrathi/word-wrap@^1.2.3":
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf"
+ integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==
+
+"@ampproject/remapping@^2.2.0":
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630"
+ integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.0"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@angular-devkit/core@16.2.8":
+ version "16.2.8"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-16.2.8.tgz#db74f3063e7fd573be7dafd022e8dc10e43140c0"
+ integrity sha512-PTGozYvh1Bin5lB15PwcXa26Ayd17bWGLS3H8Rs0s+04mUDvfNofmweaX1LgumWWy3nCUTDuwHxX10M3G0wE2g==
+ dependencies:
+ ajv "8.12.0"
+ ajv-formats "2.1.1"
+ jsonc-parser "3.2.0"
+ picomatch "2.3.1"
+ rxjs "7.8.1"
+ source-map "0.7.4"
+
+"@angular-devkit/schematics-cli@16.2.8":
+ version "16.2.8"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/schematics-cli/-/schematics-cli-16.2.8.tgz#5945f391d316724d7b49d578932dcb5a25a73649"
+ integrity sha512-EXURJCzWTVYCipiTT4vxQQOrF63asOUDbeOy3OtiSh7EwIUvxm3BPG6hquJqngEnI/N6bA75NJ1fBhU6Hrh7eA==
+ dependencies:
+ "@angular-devkit/core" "16.2.8"
+ "@angular-devkit/schematics" "16.2.8"
+ ansi-colors "4.1.3"
+ inquirer "8.2.4"
+ symbol-observable "4.0.0"
+ yargs-parser "21.1.1"
+
+"@angular-devkit/schematics@16.2.8":
+ version "16.2.8"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-16.2.8.tgz#cc11cf6d00cd9131adbede9a99f3a617aedd5bc4"
+ integrity sha512-MBiKZOlR9/YMdflALr7/7w/BGAfo/BGTrlkqsIB6rDWV1dYiCgxI+033HsiNssLS6RQyCFx/e7JA2aBBzu9zEg==
+ dependencies:
+ "@angular-devkit/core" "16.2.8"
+ jsonc-parser "3.2.0"
+ magic-string "0.30.1"
+ ora "5.4.1"
+ rxjs "7.8.1"
+
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.22.13":
+ version "7.22.13"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
+ integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
+ dependencies:
+ "@babel/highlight" "^7.22.13"
+ chalk "^2.4.2"
+
+"@babel/compat-data@^7.22.9":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.3.tgz#3febd552541e62b5e883a25eb3effd7c7379db11"
+ integrity sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==
+
+"@babel/core@^7.11.6", "@babel/core@^7.12.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.3.tgz#5ec09c8803b91f51cc887dedc2654a35852849c9"
+ integrity sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==
+ dependencies:
+ "@ampproject/remapping" "^2.2.0"
+ "@babel/code-frame" "^7.22.13"
+ "@babel/generator" "^7.23.3"
+ "@babel/helper-compilation-targets" "^7.22.15"
+ "@babel/helper-module-transforms" "^7.23.3"
+ "@babel/helpers" "^7.23.2"
+ "@babel/parser" "^7.23.3"
+ "@babel/template" "^7.22.15"
+ "@babel/traverse" "^7.23.3"
+ "@babel/types" "^7.23.3"
+ convert-source-map "^2.0.0"
+ debug "^4.1.0"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.2.3"
+ semver "^6.3.1"
+
+"@babel/generator@^7.23.3", "@babel/generator@^7.7.2":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.3.tgz#86e6e83d95903fbe7613f448613b8b319f330a8e"
+ integrity sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==
+ dependencies:
+ "@babel/types" "^7.23.3"
+ "@jridgewell/gen-mapping" "^0.3.2"
+ "@jridgewell/trace-mapping" "^0.3.17"
+ jsesc "^2.5.1"
+
+"@babel/helper-compilation-targets@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52"
+ integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==
+ dependencies:
+ "@babel/compat-data" "^7.22.9"
+ "@babel/helper-validator-option" "^7.22.15"
+ browserslist "^4.21.9"
+ lru-cache "^5.1.1"
+ semver "^6.3.1"
+
+"@babel/helper-environment-visitor@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+ integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
+
+"@babel/helper-function-name@^7.23.0":
+ version "7.23.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+ integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/types" "^7.23.0"
+
+"@babel/helper-hoist-variables@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+ integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-module-imports@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0"
+ integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==
+ dependencies:
+ "@babel/types" "^7.22.15"
+
+"@babel/helper-module-transforms@^7.23.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1"
+ integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-module-imports" "^7.22.15"
+ "@babel/helper-simple-access" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/helper-validator-identifier" "^7.22.20"
+
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
+ integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
+
+"@babel/helper-simple-access@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de"
+ integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-split-export-declaration@^7.22.6":
+ version "7.22.6"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+ integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
+ dependencies:
+ "@babel/types" "^7.22.5"
+
+"@babel/helper-string-parser@^7.22.5":
+ version "7.22.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
+ integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
+
+"@babel/helper-validator-identifier@^7.22.20":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+ integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
+"@babel/helper-validator-option@^7.22.15":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040"
+ integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==
+
+"@babel/helpers@^7.23.2":
+ version "7.23.2"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.2.tgz#2832549a6e37d484286e15ba36a5330483cac767"
+ integrity sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==
+ dependencies:
+ "@babel/template" "^7.22.15"
+ "@babel/traverse" "^7.23.2"
+ "@babel/types" "^7.23.0"
+
+"@babel/highlight@^7.22.13":
+ version "7.22.20"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
+ integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.22.20"
+ chalk "^2.4.2"
+ js-tokens "^4.0.0"
+
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.3.tgz#0ce0be31a4ca4f1884b5786057cadcb6c3be58f9"
+ integrity sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==
+
+"@babel/plugin-syntax-async-generators@^7.8.4":
+ version "7.8.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
+ integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-bigint@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea"
+ integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-class-properties@^7.8.3":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10"
+ integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.12.13"
+
+"@babel/plugin-syntax-import-meta@^7.8.3":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
+ integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-json-strings@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
+ integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-jsx@^7.7.2":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473"
+ integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
+ integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
+ integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-numeric-separator@^7.8.3":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97"
+ integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-object-rest-spread@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
+ integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
+ integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-chaining@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
+ integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-top-level-await@^7.8.3":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c"
+ integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-typescript@^7.7.2":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz#24f460c85dbbc983cd2b9c4994178bcc01df958f"
+ integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.22.5"
+
+"@babel/runtime@^7.21.0":
+ version "7.23.2"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885"
+ integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
+"@babel/template@^7.22.15", "@babel/template@^7.3.3":
+ version "7.22.15"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
+ integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/parser" "^7.22.15"
+ "@babel/types" "^7.22.15"
+
+"@babel/traverse@^7.23.2", "@babel/traverse@^7.23.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.3.tgz#26ee5f252e725aa7aca3474aa5b324eaf7908b5b"
+ integrity sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==
+ dependencies:
+ "@babel/code-frame" "^7.22.13"
+ "@babel/generator" "^7.23.3"
+ "@babel/helper-environment-visitor" "^7.22.20"
+ "@babel/helper-function-name" "^7.23.0"
+ "@babel/helper-hoist-variables" "^7.22.5"
+ "@babel/helper-split-export-declaration" "^7.22.6"
+ "@babel/parser" "^7.23.3"
+ "@babel/types" "^7.23.3"
+ debug "^4.1.0"
+ globals "^11.1.0"
+
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3", "@babel/types@^7.3.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.3.tgz#d5ea892c07f2ec371ac704420f4dcdb07b5f9598"
+ integrity sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==
+ dependencies:
+ "@babel/helper-string-parser" "^7.22.5"
+ "@babel/helper-validator-identifier" "^7.22.20"
+ to-fast-properties "^2.0.0"
+
+"@bcoe/v8-coverage@^0.2.3":
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
+ integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
+
+"@colors/colors@1.5.0":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
+ integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
+
+"@colors/colors@1.6.0", "@colors/colors@^1.6.0":
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0"
+ integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==
+
+"@cspotcode/source-map-support@^0.8.0":
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
+ integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
+ dependencies:
+ "@jridgewell/trace-mapping" "0.3.9"
+
+"@dabh/diagnostics@^2.0.2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a"
+ integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==
+ dependencies:
+ colorspace "1.1.x"
+ enabled "2.0.x"
+ kuler "^2.0.0"
+
+"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
+ integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
+ dependencies:
+ eslint-visitor-keys "^3.3.0"
+
+"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1":
+ version "4.10.0"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63"
+ integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==
+
+"@eslint/eslintrc@^2.1.3":
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz#797470a75fe0fbd5a53350ee715e85e87baff22d"
+ integrity sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==
+ dependencies:
+ ajv "^6.12.4"
+ debug "^4.3.2"
+ espree "^9.6.0"
+ globals "^13.19.0"
+ ignore "^5.2.0"
+ import-fresh "^3.2.1"
+ js-yaml "^4.1.0"
+ minimatch "^3.1.2"
+ strip-json-comments "^3.1.1"
+
+"@eslint/js@8.53.0":
+ version "8.53.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d"
+ integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==
+
+"@humanwhocodes/config-array@^0.11.13":
+ version "0.11.13"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297"
+ integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==
+ dependencies:
+ "@humanwhocodes/object-schema" "^2.0.1"
+ debug "^4.1.1"
+ minimatch "^3.0.5"
+
+"@humanwhocodes/module-importer@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
+
+"@humanwhocodes/object-schema@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044"
+ integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==
+
+"@isaacs/cliui@^8.0.2":
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
+ integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
+ dependencies:
+ string-width "^5.1.2"
+ string-width-cjs "npm:string-width@^4.2.0"
+ strip-ansi "^7.0.1"
+ strip-ansi-cjs "npm:strip-ansi@^6.0.1"
+ wrap-ansi "^8.1.0"
+ wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
+
+"@istanbuljs/load-nyc-config@^1.0.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
+ integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==
+ dependencies:
+ camelcase "^5.3.1"
+ find-up "^4.1.0"
+ get-package-type "^0.1.0"
+ js-yaml "^3.13.1"
+ resolve-from "^5.0.0"
+
+"@istanbuljs/schema@^0.1.2":
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
+ integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
+
+"@jest/console@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc"
+ integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+ slash "^3.0.0"
+
+"@jest/core@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f"
+ integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==
+ dependencies:
+ "@jest/console" "^29.7.0"
+ "@jest/reporters" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ ansi-escapes "^4.2.1"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ exit "^0.1.2"
+ graceful-fs "^4.2.9"
+ jest-changed-files "^29.7.0"
+ jest-config "^29.7.0"
+ jest-haste-map "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-regex-util "^29.6.3"
+ jest-resolve "^29.7.0"
+ jest-resolve-dependencies "^29.7.0"
+ jest-runner "^29.7.0"
+ jest-runtime "^29.7.0"
+ jest-snapshot "^29.7.0"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
+ jest-watcher "^29.7.0"
+ micromatch "^4.0.4"
+ pretty-format "^29.7.0"
+ slash "^3.0.0"
+ strip-ansi "^6.0.0"
+
+"@jest/environment@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7"
+ integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==
+ dependencies:
+ "@jest/fake-timers" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ jest-mock "^29.7.0"
+
+"@jest/expect-utils@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6"
+ integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==
+ dependencies:
+ jest-get-type "^29.6.3"
+
+"@jest/expect@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2"
+ integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==
+ dependencies:
+ expect "^29.7.0"
+ jest-snapshot "^29.7.0"
+
+"@jest/fake-timers@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565"
+ integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@sinonjs/fake-timers" "^10.0.2"
+ "@types/node" "*"
+ jest-message-util "^29.7.0"
+ jest-mock "^29.7.0"
+ jest-util "^29.7.0"
+
+"@jest/globals@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d"
+ integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/expect" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ jest-mock "^29.7.0"
+
+"@jest/reporters@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7"
+ integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==
+ dependencies:
+ "@bcoe/v8-coverage" "^0.2.3"
+ "@jest/console" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@jridgewell/trace-mapping" "^0.3.18"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ collect-v8-coverage "^1.0.0"
+ exit "^0.1.2"
+ glob "^7.1.3"
+ graceful-fs "^4.2.9"
+ istanbul-lib-coverage "^3.0.0"
+ istanbul-lib-instrument "^6.0.0"
+ istanbul-lib-report "^3.0.0"
+ istanbul-lib-source-maps "^4.0.0"
+ istanbul-reports "^3.1.3"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+ jest-worker "^29.7.0"
+ slash "^3.0.0"
+ string-length "^4.0.1"
+ strip-ansi "^6.0.0"
+ v8-to-istanbul "^9.0.1"
+
+"@jest/schemas@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
+ integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==
+ dependencies:
+ "@sinclair/typebox" "^0.27.8"
+
+"@jest/source-map@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4"
+ integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.18"
+ callsites "^3.0.0"
+ graceful-fs "^4.2.9"
+
+"@jest/test-result@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c"
+ integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==
+ dependencies:
+ "@jest/console" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ collect-v8-coverage "^1.0.0"
+
+"@jest/test-sequencer@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce"
+ integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==
+ dependencies:
+ "@jest/test-result" "^29.7.0"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^29.7.0"
+ slash "^3.0.0"
+
+"@jest/transform@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c"
+ integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==
+ dependencies:
+ "@babel/core" "^7.11.6"
+ "@jest/types" "^29.6.3"
+ "@jridgewell/trace-mapping" "^0.3.18"
+ babel-plugin-istanbul "^6.1.1"
+ chalk "^4.0.0"
+ convert-source-map "^2.0.0"
+ fast-json-stable-stringify "^2.1.0"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^29.7.0"
+ jest-regex-util "^29.6.3"
+ jest-util "^29.7.0"
+ micromatch "^4.0.4"
+ pirates "^4.0.4"
+ slash "^3.0.0"
+ write-file-atomic "^4.0.2"
+
+"@jest/types@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59"
+ integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ "@types/istanbul-reports" "^3.0.0"
+ "@types/node" "*"
+ "@types/yargs" "^17.0.8"
+ chalk "^4.0.0"
+
+"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098"
+ integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==
+ dependencies:
+ "@jridgewell/set-array" "^1.0.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
+ integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
+
+"@jridgewell/set-array@^1.0.1":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
+ integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
+
+"@jridgewell/source-map@^0.3.3":
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91"
+ integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.0"
+ "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15":
+ version "1.4.15"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@0.3.9":
+ version "0.3.9"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
+ integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.0.3"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+
+"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9":
+ version "0.3.20"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f"
+ integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@lukeed/csprng@^1.0.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe"
+ integrity sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==
+
+"@nestjs/axios@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/@nestjs/axios/-/axios-3.0.1.tgz#b006f81dd54a49def92cfaf9a8970434567e75ce"
+ integrity sha512-VlOZhAGDmOoFdsmewn8AyClAdGpKXQQaY1+3PGB+g6ceurGIdTxZgRX3VXc1T6Zs60PedWjg3A82TDOB05mrzQ==
+
+"@nestjs/cli@^10.0.0":
+ version "10.2.1"
+ resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-10.2.1.tgz#a1d32c28e188f0fb4c3f54235c55745de4c6dd7f"
+ integrity sha512-CAJAQwmxFZfB3RTvqz/eaXXWpyU+mZ4QSqfBYzjneTsPgF+uyOAW3yQpaLNn9Dfcv39R9UxSuAhayv6yuFd+Jg==
+ dependencies:
+ "@angular-devkit/core" "16.2.8"
+ "@angular-devkit/schematics" "16.2.8"
+ "@angular-devkit/schematics-cli" "16.2.8"
+ "@nestjs/schematics" "^10.0.1"
+ chalk "4.1.2"
+ chokidar "3.5.3"
+ cli-table3 "0.6.3"
+ commander "4.1.1"
+ fork-ts-checker-webpack-plugin "9.0.2"
+ glob "10.3.10"
+ inquirer "8.2.6"
+ node-emoji "1.11.0"
+ ora "5.4.1"
+ os-name "4.0.1"
+ rimraf "4.4.1"
+ shelljs "0.8.5"
+ source-map-support "0.5.21"
+ tree-kill "1.2.2"
+ tsconfig-paths "4.2.0"
+ tsconfig-paths-webpack-plugin "4.1.0"
+ typescript "5.2.2"
+ webpack "5.89.0"
+ webpack-node-externals "3.0.0"
+
+"@nestjs/common@^10.0.0":
+ version "10.2.8"
+ resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-10.2.8.tgz#f8934e6353440d6e51c89c0cf1b0f9aef54e8729"
+ integrity sha512-rmpwcdvq2IWMmsUVP8rsdKub6uDWk7dwCYo0aif50JTwcvcxzaP3iKVFKoSgvp0RKYu8h15+/AEOfaInmPpl0Q==
+ dependencies:
+ uid "2.0.2"
+ iterare "1.2.1"
+ tslib "2.6.2"
+
+"@nestjs/config@^3.1.1":
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/@nestjs/config/-/config-3.1.1.tgz#51e23ed84debd08afb86acf7b92bc4bf341797da"
+ integrity sha512-qu5QlNiJdqQtOsnB6lx4JCXPQ96jkKUsOGd+JXfXwqJqZcOSAq6heNFg0opW4pq4J/VZoNwoo87TNnx9wthnqQ==
+ dependencies:
+ dotenv "16.3.1"
+ dotenv-expand "10.0.0"
+ lodash "4.17.21"
+ uuid "9.0.0"
+
+"@nestjs/core@^10.0.0":
+ version "10.2.8"
+ resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-10.2.8.tgz#7b3abcf375113faffeef989a3a945c2494d390ec"
+ integrity sha512-9+MZ2s8ixfY9Bl/M9ofChiyYymcwdK9ZWNH4GDMF7Am7XRAQ1oqde6MYGG05rhQwiVXuTwaYLlXciJKfsrg5qg==
+ dependencies:
+ uid "2.0.2"
+ "@nuxtjs/opencollective" "0.3.2"
+ fast-safe-stringify "2.1.1"
+ iterare "1.2.1"
+ path-to-regexp "3.2.0"
+ tslib "2.6.2"
+
+"@nestjs/jwt@^10.2.0":
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/@nestjs/jwt/-/jwt-10.2.0.tgz#6aa35a04922d19c6426efced4671620f92e6dbd0"
+ integrity sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==
+ dependencies:
+ "@types/jsonwebtoken" "9.0.5"
+ jsonwebtoken "9.0.2"
+
+"@nestjs/mapped-types@*":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.0.3.tgz#f400432da6c98d02b94b14e893fd7fa46c152403"
+ integrity sha512-40Zdqg98lqoF0+7ThWIZFStxgzisK6GG22+1ABO4kZiGF/Tu2FE+DYLw+Q9D94vcFWizJ+MSjNN4ns9r6hIGxw==
+
+"@nestjs/platform-express@^10.0.0":
+ version "10.2.8"
+ resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.2.8.tgz#c5af1fe3afb6e9858fc5610fd11a247635187eff"
+ integrity sha512-WoSSVtwIRc5AdGMHWVzWZK4JZLT0f4o2xW8P9gQvcX+omL8W1kXCfY8GQYXNBG84XmBNYH8r0FtC8oMe/lH5NQ==
+ dependencies:
+ body-parser "1.20.2"
+ cors "2.8.5"
+ express "4.18.2"
+ multer "1.4.4-lts.1"
+ tslib "2.6.2"
+
+"@nestjs/platform-ws@^10.2.10":
+ version "10.2.10"
+ resolved "https://registry.yarnpkg.com/@nestjs/platform-ws/-/platform-ws-10.2.10.tgz#d6a4df6bebcf85e27fd437cf764d29921a924889"
+ integrity sha512-x9L7jixAEtbNjP9hIm9Fmx+kL9ruFQLu2cUb0EdSNtwK/efAJZ3+Taz9T8g/Nm5DG4k0356X6hmRk74ChJHg9g==
+ dependencies:
+ tslib "2.6.2"
+ ws "8.14.2"
+
+"@nestjs/schematics@^10.0.0", "@nestjs/schematics@^10.0.1":
+ version "10.0.3"
+ resolved "https://registry.yarnpkg.com/@nestjs/schematics/-/schematics-10.0.3.tgz#0f48af0a20983ffecabcd8763213a3e53d43f270"
+ integrity sha512-2BRujK0GqGQ7j1Zpz+obVfskDnnOeVKt5aXoSaVngKo8Oczy8uYCY+R547TQB+Kf35epdfFER2pVnQrX3/It5A==
+ dependencies:
+ "@angular-devkit/core" "16.2.8"
+ "@angular-devkit/schematics" "16.2.8"
+ comment-json "4.2.3"
+ jsonc-parser "3.2.0"
+ pluralize "8.0.0"
+
+"@nestjs/testing@^10.0.0":
+ version "10.2.8"
+ resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-10.2.8.tgz#9bf0a05770b5afacf85aaf4abd99caa2284c3dd5"
+ integrity sha512-9Kj5IQhM67/nj/MT6Wi2OmWr5YQnCMptwKVFrX1TDaikpY12196v7frk0jVjdT7wms7rV07GZle9I2z0aSjqtQ==
+ dependencies:
+ tslib "2.6.2"
+
+"@nestjs/typeorm@^10.0.0":
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/@nestjs/typeorm/-/typeorm-10.0.0.tgz#78e20d3413d59dd3dfee03260c904f0f4040b4e1"
+ integrity sha512-WQU4HCDTz4UavsFzvGUKDHqi0MO5K47yFoPXdmh+Z/hCNO7SHCMmV9jLiLukM8n5nKUqJ3jDqiljkWBcZPdCtA==
+ dependencies:
+ uuid "9.0.0"
+
+"@nestjs/websockets@^10.2.10":
+ version "10.2.10"
+ resolved "https://registry.yarnpkg.com/@nestjs/websockets/-/websockets-10.2.10.tgz#f4aee5956adcb767a26d5a3e138f82a807b8e488"
+ integrity sha512-L1AkxwLUj/ntk26jO1SXYl3GRElQE6Fikzfy/3MPFURk0GDs7tHUzLcb8BC8q8u5ZpUjBAC2wFVQzrY5R0MHNw==
+ dependencies:
+ iterare "1.2.1"
+ object-hash "3.0.0"
+ tslib "2.6.2"
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@nuxtjs/opencollective@0.3.2":
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz#620ce1044f7ac77185e825e1936115bb38e2681c"
+ integrity sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==
+ dependencies:
+ chalk "^4.1.0"
+ consola "^2.15.0"
+ node-fetch "^2.6.1"
+
+"@panva/asn1.js@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@panva/asn1.js/-/asn1.js-1.0.0.tgz#dd55ae7b8129e02049f009408b97c61ccf9032f6"
+ integrity sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==
+
+"@panva/jose@^1.9.3":
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/@panva/jose/-/jose-1.9.3.tgz#572182543d4b04ab9d414a358be794ed1bbb5eb3"
+ integrity sha512-oKzjM5YsCSaL+/7NDQhfqeu0xj7owqRduNLM/W+dtIyGI7/AIaPue/bz4fqjYVDTpmRtrlsserR6kiqJucmbjA==
+ dependencies:
+ jose "^1.15.0"
+
+"@pkgjs/parseargs@^0.11.0":
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
+ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+
+"@pkgr/utils@^2.3.1":
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc"
+ integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==
+ dependencies:
+ cross-spawn "^7.0.3"
+ fast-glob "^3.3.0"
+ is-glob "^4.0.3"
+ open "^9.1.0"
+ picocolors "^1.0.0"
+ tslib "^2.6.0"
+
+"@redis/bloom@1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71"
+ integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==
+
+"@redis/client@1.5.12":
+ version "1.5.12"
+ resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.5.12.tgz#4c387727992152aea443b869de0ebb697f899187"
+ integrity sha512-/ZjE18HRzMd80eXIIUIPcH81UoZpwulbo8FmbElrjPqH0QC0SeIKu1BOU49bO5trM5g895kAjhvalt5h77q+4A==
+ dependencies:
+ cluster-key-slot "1.1.2"
+ generic-pool "3.9.0"
+ yallist "4.0.0"
+
+"@redis/graph@1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.1.tgz#8c10df2df7f7d02741866751764031a957a170ea"
+ integrity sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==
+
+"@redis/json@1.0.6":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.6.tgz#b7a7725bbb907765d84c99d55eac3fcf772e180e"
+ integrity sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==
+
+"@redis/search@1.1.6":
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.1.6.tgz#33bcdd791d9ed88ab6910243a355d85a7fedf756"
+ integrity sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw==
+
+"@redis/time-series@1.0.5":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.5.tgz#a6d70ef7a0e71e083ea09b967df0a0ed742bc6ad"
+ integrity sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==
+
+"@sinclair/typebox@^0.27.8":
+ version "0.27.8"
+ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
+ integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
+
+"@sinonjs/commons@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72"
+ integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==
+ dependencies:
+ type-detect "4.0.8"
+
+"@sinonjs/fake-timers@^10.0.2":
+ version "10.3.0"
+ resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66"
+ integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==
+ dependencies:
+ "@sinonjs/commons" "^3.0.0"
+
+"@sqltools/formatter@^1.2.5":
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.5.tgz#3abc203c79b8c3e90fd6c156a0c62d5403520e12"
+ integrity sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==
+
+"@tsconfig/node10@^1.0.7":
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
+ integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
+
+"@tsconfig/node12@^1.0.7":
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
+ integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
+
+"@tsconfig/node14@^1.0.0":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
+ integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
+
+"@tsconfig/node16@^1.0.2":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9"
+ integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==
+
+"@types/babel__core@^7.1.14":
+ version "7.20.4"
+ resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.4.tgz#26a87347e6c6f753b3668398e34496d6d9ac6ac0"
+ integrity sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==
+ dependencies:
+ "@babel/parser" "^7.20.7"
+ "@babel/types" "^7.20.7"
+ "@types/babel__generator" "*"
+ "@types/babel__template" "*"
+ "@types/babel__traverse" "*"
+
+"@types/babel__generator@*":
+ version "7.6.7"
+ resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.7.tgz#a7aebf15c7bc0eb9abd638bdb5c0b8700399c9d0"
+ integrity sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==
+ dependencies:
+ "@babel/types" "^7.0.0"
+
+"@types/babel__template@*":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f"
+ integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==
+ dependencies:
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+
+"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6":
+ version "7.20.4"
+ resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.4.tgz#ec2c06fed6549df8bc0eb4615b683749a4a92e1b"
+ integrity sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==
+ dependencies:
+ "@babel/types" "^7.20.7"
+
+"@types/body-parser@*":
+ version "1.19.5"
+ resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4"
+ integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==
+ dependencies:
+ "@types/connect" "*"
+ "@types/node" "*"
+
+"@types/connect@*":
+ version "3.4.38"
+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858"
+ integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==
+ dependencies:
+ "@types/node" "*"
+
+"@types/cookiejar@*":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.4.tgz#d3fe9c70f026237239ef57dd9d41c87f978b63b5"
+ integrity sha512-b698BLJ6kPVd6uhHsY7wlebZdrWPXYied883PDSzpJZYOP97EOn/oGdLCH3jJf157srkFReIZY5v0H1s8Dozrg==
+
+"@types/eslint-scope@^3.7.3":
+ version "3.7.7"
+ resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5"
+ integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==
+ dependencies:
+ "@types/eslint" "*"
+ "@types/estree" "*"
+
+"@types/eslint@*":
+ version "8.44.7"
+ resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.44.7.tgz#430b3cc96db70c81f405e6a08aebdb13869198f5"
+ integrity sha512-f5ORu2hcBbKei97U73mf+l9t4zTGl74IqZ0GQk4oVea/VS8tQZYkUveSYojk+frraAVYId0V2WC9O4PTNru2FQ==
+ dependencies:
+ "@types/estree" "*"
+ "@types/json-schema" "*"
+
+"@types/estree@*", "@types/estree@^1.0.0":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
+ integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
+
+"@types/express-serve-static-core@^4.17.33":
+ version "4.17.41"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz#5077defa630c2e8d28aa9ffc2c01c157c305bef6"
+ integrity sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==
+ dependencies:
+ "@types/node" "*"
+ "@types/qs" "*"
+ "@types/range-parser" "*"
+ "@types/send" "*"
+
+"@types/express@^4.17.17":
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d"
+ integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==
+ dependencies:
+ "@types/body-parser" "*"
+ "@types/express-serve-static-core" "^4.17.33"
+ "@types/qs" "*"
+ "@types/serve-static" "*"
+
+"@types/graceful-fs@^4.1.3":
+ version "4.1.9"
+ resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4"
+ integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/http-errors@*":
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
+ integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==
+
+"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7"
+ integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==
+
+"@types/istanbul-lib-report@*":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf"
+ integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==
+ dependencies:
+ "@types/istanbul-lib-coverage" "*"
+
+"@types/istanbul-reports@^3.0.0":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54"
+ integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==
+ dependencies:
+ "@types/istanbul-lib-report" "*"
+
+"@types/jest@^29.5.2":
+ version "29.5.8"
+ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.8.tgz#ed5c256fe2bc7c38b1915ee5ef1ff24a3427e120"
+ integrity sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g==
+ dependencies:
+ expect "^29.0.0"
+ pretty-format "^29.0.0"
+
+"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.8":
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
+ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
+
+"@types/jsonwebtoken@9.0.5":
+ version "9.0.5"
+ resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz#0bd9b841c9e6c5a937c17656e2368f65da025588"
+ integrity sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==
+ dependencies:
+ "@types/node" "*"
+
+"@types/mime@*":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45"
+ integrity sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==
+
+"@types/mime@^1":
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
+ integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
+
+"@types/node@*", "@types/node@^20.3.1":
+ version "20.9.0"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298"
+ integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==
+ dependencies:
+ undici-types "~5.26.4"
+
+"@types/qs@*":
+ version "6.9.10"
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.10.tgz#0af26845b5067e1c9a622658a51f60a3934d51e8"
+ integrity sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==
+
+"@types/range-parser@*":
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb"
+ integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
+
+"@types/semver@^7.5.0":
+ version "7.5.5"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.5.tgz#deed5ab7019756c9c90ea86139106b0346223f35"
+ integrity sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==
+
+"@types/send@*":
+ version "0.17.4"
+ resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a"
+ integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==
+ dependencies:
+ "@types/mime" "^1"
+ "@types/node" "*"
+
+"@types/serve-static@*":
+ version "1.15.5"
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033"
+ integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==
+ dependencies:
+ "@types/http-errors" "*"
+ "@types/mime" "*"
+ "@types/node" "*"
+
+"@types/stack-utils@^2.0.0":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
+ integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
+
+"@types/superagent@*":
+ version "4.1.21"
+ resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.21.tgz#78e2c2d6894c5f8ece228f0df4912906133d97c3"
+ integrity sha512-yrbAccEEY9+BSa1wji3ry8R3/BdW9kyWnjkRKctrtw5ebn/k2a2CsMeaQ7dD4iLfomgHkomBVIVgOFRMV4XYHA==
+ dependencies:
+ "@types/cookiejar" "*"
+ "@types/node" "*"
+
+"@types/supertest@^2.0.12":
+ version "2.0.16"
+ resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.16.tgz#7a1294edebecb960d957bbe9b26002a2b7f21cd7"
+ integrity sha512-6c2ogktZ06tr2ENoZivgm7YnprnhYE4ZoXGMY+oA7IuAf17M8FWvujXZGmxLv8y0PTyts4x5A+erSwVUFA8XSg==
+ dependencies:
+ "@types/superagent" "*"
+
+"@types/triple-beam@^1.3.2":
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c"
+ integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==
+
+"@types/validator@^13.7.10":
+ version "13.11.6"
+ resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.11.6.tgz#8645efedfd891bc1d7ad82539005d7ff785fe294"
+ integrity sha512-HUgHujPhKuNzgNXBRZKYexwoG+gHKU+tnfPqjWXFghZAnn73JElicMkuSKJyLGr9JgyA8IgK7fj88IyA9rwYeQ==
+
+"@types/yargs-parser@*":
+ version "21.0.3"
+ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15"
+ integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==
+
+"@types/yargs@^17.0.8":
+ version "17.0.31"
+ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.31.tgz#8fd0089803fd55d8a285895a18b88cb71a99683c"
+ integrity sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==
+ dependencies:
+ "@types/yargs-parser" "*"
+
+"@typescript-eslint/eslint-plugin@^6.0.0":
+ version "6.10.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz#cfe2bd34e26d2289212946b96ab19dcad64b661a"
+ integrity sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==
+ dependencies:
+ "@eslint-community/regexpp" "^4.5.1"
+ "@typescript-eslint/scope-manager" "6.10.0"
+ "@typescript-eslint/type-utils" "6.10.0"
+ "@typescript-eslint/utils" "6.10.0"
+ "@typescript-eslint/visitor-keys" "6.10.0"
+ debug "^4.3.4"
+ graphemer "^1.4.0"
+ ignore "^5.2.4"
+ natural-compare "^1.4.0"
+ semver "^7.5.4"
+ ts-api-utils "^1.0.1"
+
+"@typescript-eslint/parser@^6.0.0":
+ version "6.10.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.10.0.tgz#578af79ae7273193b0b6b61a742a2bc8e02f875a"
+ integrity sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==
+ dependencies:
+ "@typescript-eslint/scope-manager" "6.10.0"
+ "@typescript-eslint/types" "6.10.0"
+ "@typescript-eslint/typescript-estree" "6.10.0"
+ "@typescript-eslint/visitor-keys" "6.10.0"
+ debug "^4.3.4"
+
+"@typescript-eslint/scope-manager@6.10.0":
+ version "6.10.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz#b0276118b13d16f72809e3cecc86a72c93708540"
+ integrity sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==
+ dependencies:
+ "@typescript-eslint/types" "6.10.0"
+ "@typescript-eslint/visitor-keys" "6.10.0"
+
+"@typescript-eslint/type-utils@6.10.0":
+ version "6.10.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz#1007faede067c78bdbcef2e8abb31437e163e2e1"
+ integrity sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==
+ dependencies:
+ "@typescript-eslint/typescript-estree" "6.10.0"
+ "@typescript-eslint/utils" "6.10.0"
+ debug "^4.3.4"
+ ts-api-utils "^1.0.1"
+
+"@typescript-eslint/types@6.10.0":
+ version "6.10.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.10.0.tgz#f4f0a84aeb2ac546f21a66c6e0da92420e921367"
+ integrity sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==
+
+"@typescript-eslint/typescript-estree@6.10.0":
+ version "6.10.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz#667381eed6f723a1a8ad7590a31f312e31e07697"
+ integrity sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==
+ dependencies:
+ "@typescript-eslint/types" "6.10.0"
+ "@typescript-eslint/visitor-keys" "6.10.0"
+ debug "^4.3.4"
+ globby "^11.1.0"
+ is-glob "^4.0.3"
+ semver "^7.5.4"
+ ts-api-utils "^1.0.1"
+
+"@typescript-eslint/utils@6.10.0":
+ version "6.10.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.10.0.tgz#4d76062d94413c30e402c9b0df8c14aef8d77336"
+ integrity sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.4.0"
+ "@types/json-schema" "^7.0.12"
+ "@types/semver" "^7.5.0"
+ "@typescript-eslint/scope-manager" "6.10.0"
+ "@typescript-eslint/types" "6.10.0"
+ "@typescript-eslint/typescript-estree" "6.10.0"
+ semver "^7.5.4"
+
+"@typescript-eslint/visitor-keys@6.10.0":
+ version "6.10.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz#b9eaf855a1ac7e95633ae1073af43d451e8f84e3"
+ integrity sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==
+ dependencies:
+ "@typescript-eslint/types" "6.10.0"
+ eslint-visitor-keys "^3.4.1"
+
+"@ungap/structured-clone@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
+ integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
+
+"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
+ integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==
+ dependencies:
+ "@webassemblyjs/helper-numbers" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+
+"@webassemblyjs/floating-point-hex-parser@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431"
+ integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==
+
+"@webassemblyjs/helper-api-error@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768"
+ integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==
+
+"@webassemblyjs/helper-buffer@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093"
+ integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==
+
+"@webassemblyjs/helper-numbers@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5"
+ integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==
+ dependencies:
+ "@webassemblyjs/floating-point-hex-parser" "1.11.6"
+ "@webassemblyjs/helper-api-error" "1.11.6"
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/helper-wasm-bytecode@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9"
+ integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==
+
+"@webassemblyjs/helper-wasm-section@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577"
+ integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-buffer" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.11.6"
+
+"@webassemblyjs/ieee754@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a"
+ integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==
+ dependencies:
+ "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7"
+ integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==
+ dependencies:
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a"
+ integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==
+
+"@webassemblyjs/wasm-edit@^1.11.5":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab"
+ integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-buffer" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/helper-wasm-section" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.11.6"
+ "@webassemblyjs/wasm-opt" "1.11.6"
+ "@webassemblyjs/wasm-parser" "1.11.6"
+ "@webassemblyjs/wast-printer" "1.11.6"
+
+"@webassemblyjs/wasm-gen@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268"
+ integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/ieee754" "1.11.6"
+ "@webassemblyjs/leb128" "1.11.6"
+ "@webassemblyjs/utf8" "1.11.6"
+
+"@webassemblyjs/wasm-opt@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2"
+ integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-buffer" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.11.6"
+ "@webassemblyjs/wasm-parser" "1.11.6"
+
+"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1"
+ integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@webassemblyjs/helper-api-error" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/ieee754" "1.11.6"
+ "@webassemblyjs/leb128" "1.11.6"
+ "@webassemblyjs/utf8" "1.11.6"
+
+"@webassemblyjs/wast-printer@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20"
+ integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==
+ dependencies:
+ "@webassemblyjs/ast" "1.11.6"
+ "@xtuc/long" "4.2.2"
+
+"@xtuc/ieee754@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+ integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
+
+"@xtuc/long@4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+ integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+
+accepts@~1.3.8:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+ dependencies:
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
+
+acorn-import-assertions@^1.9.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac"
+ integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==
+
+acorn-jsx@^5.3.2:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
+ integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
+
+acorn-walk@^8.1.1:
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.0.tgz#2097665af50fd0cf7a2dfccd2b9368964e66540f"
+ integrity sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==
+
+acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0:
+ version "8.11.2"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b"
+ integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==
+
+ajv-formats@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
+ integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==
+ dependencies:
+ ajv "^8.0.0"
+
+ajv-keywords@^3.5.2:
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
+ integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
+
+ajv@8.12.0, ajv@^8.0.0:
+ version "8.12.0"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
+ integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+ uri-js "^4.2.2"
+
+ajv@^6.12.4, ajv@^6.12.5:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ansi-colors@4.1.3:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
+ integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
+
+ansi-escapes@^4.2.1:
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
+ integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
+ dependencies:
+ type-fest "^0.21.3"
+
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-regex@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
+ integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
+ansi-styles@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
+ integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
+
+ansi-styles@^6.1.0:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
+ integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
+
+any-promise@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+ integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
+
+anymatch@^3.0.3, anymatch@~3.1.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+app-root-path@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86"
+ integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==
+
+append-field@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
+ integrity sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==
+
+arg@^4.1.0:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
+ integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+argparse@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+ integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
+
+array-timsort@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/array-timsort/-/array-timsort-1.0.3.tgz#3c9e4199e54fb2b9c3fe5976396a21614ef0d926"
+ integrity sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==
+
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+asap@^2.0.0:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
+ integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
+
+async@^3.2.3:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66"
+ integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+axios@^1.6.2:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2"
+ integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==
+ dependencies:
+ follow-redirects "^1.15.0"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
+babel-jest@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5"
+ integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==
+ dependencies:
+ "@jest/transform" "^29.7.0"
+ "@types/babel__core" "^7.1.14"
+ babel-plugin-istanbul "^6.1.1"
+ babel-preset-jest "^29.6.3"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ slash "^3.0.0"
+
+babel-plugin-istanbul@^6.1.1:
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73"
+ integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@istanbuljs/load-nyc-config" "^1.0.0"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-instrument "^5.0.4"
+ test-exclude "^6.0.0"
+
+babel-plugin-jest-hoist@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626"
+ integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==
+ dependencies:
+ "@babel/template" "^7.3.3"
+ "@babel/types" "^7.3.3"
+ "@types/babel__core" "^7.1.14"
+ "@types/babel__traverse" "^7.0.6"
+
+babel-preset-current-node-syntax@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b"
+ integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==
+ dependencies:
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+ "@babel/plugin-syntax-bigint" "^7.8.3"
+ "@babel/plugin-syntax-class-properties" "^7.8.3"
+ "@babel/plugin-syntax-import-meta" "^7.8.3"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-syntax-numeric-separator" "^7.8.3"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+ "@babel/plugin-syntax-top-level-await" "^7.8.3"
+
+babel-preset-jest@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c"
+ integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==
+ dependencies:
+ babel-plugin-jest-hoist "^29.6.3"
+ babel-preset-current-node-syntax "^1.0.0"
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+base64-js@^1.3.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+ integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
+big-integer@^1.6.44:
+ version "1.6.51"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
+ integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
+
+binary-extensions@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
+ integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+
+bl@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
+ integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
+ dependencies:
+ buffer "^5.5.0"
+ inherits "^2.0.4"
+ readable-stream "^3.4.0"
+
+body-parser@1.20.1:
+ version "1.20.1"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
+ integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
+ dependencies:
+ bytes "3.1.2"
+ content-type "~1.0.4"
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ on-finished "2.4.1"
+ qs "6.11.0"
+ raw-body "2.5.1"
+ type-is "~1.6.18"
+ unpipe "1.0.0"
+
+body-parser@1.20.2:
+ version "1.20.2"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
+ integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
+ dependencies:
+ bytes "3.1.2"
+ content-type "~1.0.5"
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ on-finished "2.4.1"
+ qs "6.11.0"
+ raw-body "2.5.2"
+ type-is "~1.6.18"
+ unpipe "1.0.0"
+
+bplist-parser@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e"
+ integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==
+ dependencies:
+ big-integer "^1.6.44"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+brace-expansion@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+ integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+ dependencies:
+ balanced-match "^1.0.0"
+
+braces@^3.0.2, braces@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+ integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+ dependencies:
+ fill-range "^7.0.1"
+
+browserslist@^4.14.5, browserslist@^4.21.9:
+ version "4.22.1"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619"
+ integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==
+ dependencies:
+ caniuse-lite "^1.0.30001541"
+ electron-to-chromium "^1.4.535"
+ node-releases "^2.0.13"
+ update-browserslist-db "^1.0.13"
+
+bs-logger@0.x:
+ version "0.2.6"
+ resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8"
+ integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==
+ dependencies:
+ fast-json-stable-stringify "2.x"
+
+bser@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
+ integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==
+ dependencies:
+ node-int64 "^0.4.0"
+
+buffer-equal-constant-time@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
+ integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
+
+buffer-from@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
+buffer-writer@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04"
+ integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==
+
+buffer@^5.5.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+ integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.1.13"
+
+buffer@^6.0.3:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
+ integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.2.1"
+
+bundle-name@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a"
+ integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==
+ dependencies:
+ run-applescript "^5.0.0"
+
+busboy@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
+ integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
+ dependencies:
+ streamsearch "^1.1.0"
+
+bytes@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
+call-bind@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513"
+ integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==
+ dependencies:
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.1"
+ set-function-length "^1.1.1"
+
+callsites@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camelcase@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+camelcase@^6.2.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
+ integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+
+caniuse-lite@^1.0.30001541:
+ version "1.0.30001561"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da"
+ integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==
+
+chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
+chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+char-regex@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
+ integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
+
+chardet@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+ integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
+chokidar@3.5.3, chokidar@^3.5.3:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+chrome-trace-event@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
+ integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
+
+ci-info@^3.2.0:
+ version "3.9.0"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4"
+ integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
+
+cjs-module-lexer@^1.0.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107"
+ integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==
+
+class-transformer@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336"
+ integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==
+
+class-validator@^0.14.0:
+ version "0.14.0"
+ resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.0.tgz#40ed0ecf3c83b2a8a6a320f4edb607be0f0df159"
+ integrity sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==
+ dependencies:
+ "@types/validator" "^13.7.10"
+ libphonenumber-js "^1.10.14"
+ validator "^13.7.0"
+
+cli-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+ integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
+ dependencies:
+ restore-cursor "^3.1.0"
+
+cli-highlight@^2.1.11:
+ version "2.1.11"
+ resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf"
+ integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==
+ dependencies:
+ chalk "^4.0.0"
+ highlight.js "^10.7.1"
+ mz "^2.4.0"
+ parse5 "^5.1.1"
+ parse5-htmlparser2-tree-adapter "^6.0.0"
+ yargs "^16.0.0"
+
+cli-spinners@^2.5.0:
+ version "2.9.1"
+ resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.1.tgz#9c0b9dad69a6d47cbb4333c14319b060ed395a35"
+ integrity sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==
+
+cli-table3@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2"
+ integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==
+ dependencies:
+ string-width "^4.2.0"
+ optionalDependencies:
+ "@colors/colors" "1.5.0"
+
+cli-width@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
+ integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
+
+cliui@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+ integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^7.0.0"
+
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
+clone@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+ integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
+
+cluster-key-slot@1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
+ integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+ integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
+
+collect-v8-coverage@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9"
+ integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==
+
+color-convert@^1.9.0, color-convert@^1.9.3:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+color-name@^1.0.0, color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+color-string@^1.6.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@^3.1.3:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164"
+ integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==
+ dependencies:
+ color-convert "^1.9.3"
+ color-string "^1.6.0"
+
+colorspace@1.1.x:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243"
+ integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==
+ dependencies:
+ color "^3.1.3"
+ text-hex "1.0.x"
+
+combined-stream@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+ dependencies:
+ delayed-stream "~1.0.0"
+
+commander@4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
+ integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
+
+commander@^2.20.0:
+ version "2.20.3"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+ integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+comment-json@4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.2.3.tgz#50b487ebbf43abe44431f575ebda07d30d015365"
+ integrity sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==
+ dependencies:
+ array-timsort "^1.0.3"
+ core-util-is "^1.0.3"
+ esprima "^4.0.1"
+ has-own-prop "^2.0.0"
+ repeat-string "^1.6.1"
+
+component-emitter@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+ integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+concat-stream@^1.5.2:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+ integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
+ dependencies:
+ buffer-from "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^2.2.2"
+ typedarray "^0.0.6"
+
+consola@^2.15.0:
+ version "2.15.3"
+ resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550"
+ integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==
+
+content-disposition@0.5.4:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+ integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
+ dependencies:
+ safe-buffer "5.2.1"
+
+content-type@~1.0.4, content-type@~1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
+convert-source-map@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
+ integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
+
+cookie-parser@^1.4.6:
+ version "1.4.6"
+ resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.6.tgz#3ac3a7d35a7a03bbc7e365073a26074824214594"
+ integrity sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==
+ dependencies:
+ cookie "0.4.1"
+ cookie-signature "1.0.6"
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
+
+cookie@0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
+ integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
+
+cookie@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
+ integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
+
+cookiejar@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b"
+ integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==
+
+core-util-is@^1.0.3, core-util-is@~1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
+ integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
+
+cors@2.8.5:
+ version "2.8.5"
+ resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
+ integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
+ dependencies:
+ object-assign "^4"
+ vary "^1"
+
+cosmiconfig@^8.2.0:
+ version "8.3.6"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3"
+ integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==
+ dependencies:
+ import-fresh "^3.3.0"
+ js-yaml "^4.1.0"
+ parse-json "^5.2.0"
+ path-type "^4.0.0"
+
+create-jest@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320"
+ integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ chalk "^4.0.0"
+ exit "^0.1.2"
+ graceful-fs "^4.2.9"
+ jest-config "^29.7.0"
+ jest-util "^29.7.0"
+ prompts "^2.0.1"
+
+create-require@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
+ integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
+
+cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
+date-fns@^2.29.3:
+ version "2.30.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
+ integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
+ dependencies:
+ "@babel/runtime" "^7.21.0"
+
+debug@2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+ dependencies:
+ ms "2.1.2"
+
+dedent@^1.0.0:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff"
+ integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==
+
+deep-is@^0.1.3:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+ integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+
+deepmerge@^4.2.2:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
+ integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+
+default-browser-id@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c"
+ integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==
+ dependencies:
+ bplist-parser "^0.2.0"
+ untildify "^4.0.0"
+
+default-browser@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da"
+ integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==
+ dependencies:
+ bundle-name "^3.0.0"
+ default-browser-id "^3.0.0"
+ execa "^7.1.1"
+ titleize "^3.0.0"
+
+defaults@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a"
+ integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==
+ dependencies:
+ clone "^1.0.2"
+
+define-data-property@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3"
+ integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==
+ dependencies:
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+define-lazy-prop@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f"
+ integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+depd@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
+destroy@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+ integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
+detect-newline@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
+ integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
+
+dezalgo@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81"
+ integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==
+ dependencies:
+ asap "^2.0.0"
+ wrappy "1"
+
+diff-sequences@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
+ integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
+
+diff@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+ integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+ dependencies:
+ path-type "^4.0.0"
+
+doctrine@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+ dependencies:
+ esutils "^2.0.2"
+
+dotenv-expand@10.0.0:
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37"
+ integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==
+
+dotenv@16.3.1, dotenv@^16.0.3:
+ version "16.3.1"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
+ integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
+
+eastasianwidth@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
+ integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
+
+ecdsa-sig-formatter@1.0.11:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
+ integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
+ dependencies:
+ safe-buffer "^5.0.1"
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
+
+electron-to-chromium@^1.4.535:
+ version "1.4.579"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.579.tgz#40ddec29bb5549908e82ccd652cf5da2e5900c23"
+ integrity sha512-bJKvA+awBIzYR0xRced7PrQuRIwGQPpo6ZLP62GAShahU9fWpsNN2IP6BSP1BLDDSbxvBVRGAMWlvVVq3npmLA==
+
+emittery@^0.13.1:
+ version "0.13.1"
+ resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad"
+ integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==
+
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+emoji-regex@^9.2.2:
+ version "9.2.2"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
+ integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+
+enabled@2.0.x:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2"
+ integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
+
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
+
+end-of-stream@^1.1.0:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+ integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+ dependencies:
+ once "^1.4.0"
+
+enhanced-resolve@^5.0.0, enhanced-resolve@^5.15.0, enhanced-resolve@^5.7.0:
+ version "5.15.0"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35"
+ integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==
+ dependencies:
+ graceful-fs "^4.2.4"
+ tapable "^2.2.0"
+
+error-ex@^1.3.1:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+ integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+ dependencies:
+ is-arrayish "^0.2.1"
+
+es-module-lexer@^1.2.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.1.tgz#c1b0dd5ada807a3b3155315911f364dc4e909db1"
+ integrity sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==
+
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
+
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+escape-string-regexp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
+ integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
+
+escape-string-regexp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+eslint-config-prettier@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz#eb25485946dd0c66cd216a46232dc05451518d1f"
+ integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==
+
+eslint-plugin-prettier@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz#a3b399f04378f79f066379f544e42d6b73f11515"
+ integrity sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==
+ dependencies:
+ prettier-linter-helpers "^1.0.0"
+ synckit "^0.8.5"
+
+eslint-scope@5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+ integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^4.1.1"
+
+eslint-scope@^7.2.2:
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
+ integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^5.2.0"
+
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
+ integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
+
+eslint@^8.42.0:
+ version "8.53.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce"
+ integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@eslint-community/regexpp" "^4.6.1"
+ "@eslint/eslintrc" "^2.1.3"
+ "@eslint/js" "8.53.0"
+ "@humanwhocodes/config-array" "^0.11.13"
+ "@humanwhocodes/module-importer" "^1.0.1"
+ "@nodelib/fs.walk" "^1.2.8"
+ "@ungap/structured-clone" "^1.2.0"
+ ajv "^6.12.4"
+ chalk "^4.0.0"
+ cross-spawn "^7.0.2"
+ debug "^4.3.2"
+ doctrine "^3.0.0"
+ escape-string-regexp "^4.0.0"
+ eslint-scope "^7.2.2"
+ eslint-visitor-keys "^3.4.3"
+ espree "^9.6.1"
+ esquery "^1.4.2"
+ esutils "^2.0.2"
+ fast-deep-equal "^3.1.3"
+ file-entry-cache "^6.0.1"
+ find-up "^5.0.0"
+ glob-parent "^6.0.2"
+ globals "^13.19.0"
+ graphemer "^1.4.0"
+ ignore "^5.2.0"
+ imurmurhash "^0.1.4"
+ is-glob "^4.0.0"
+ is-path-inside "^3.0.3"
+ js-yaml "^4.1.0"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.4.1"
+ lodash.merge "^4.6.2"
+ minimatch "^3.1.2"
+ natural-compare "^1.4.0"
+ optionator "^0.9.3"
+ strip-ansi "^6.0.1"
+ text-table "^0.2.0"
+
+espree@^9.6.0, espree@^9.6.1:
+ version "9.6.1"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
+ integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
+ dependencies:
+ acorn "^8.9.0"
+ acorn-jsx "^5.3.2"
+ eslint-visitor-keys "^3.4.1"
+
+esprima@^4.0.0, esprima@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esquery@^1.4.2:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
+ integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
+ dependencies:
+ estraverse "^5.1.0"
+
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+ dependencies:
+ estraverse "^5.2.0"
+
+estraverse@^4.1.1:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+estraverse@^5.1.0, estraverse@^5.2.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+esutils@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+ integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+etag@~1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+ integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
+
+events@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
+ integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+
+execa@^4.0.2:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a"
+ integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==
+ dependencies:
+ cross-spawn "^7.0.0"
+ get-stream "^5.0.0"
+ human-signals "^1.1.1"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.0"
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+ strip-final-newline "^2.0.0"
+
+execa@^5.0.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+ integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.0"
+ human-signals "^2.1.0"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.1"
+ onetime "^5.1.2"
+ signal-exit "^3.0.3"
+ strip-final-newline "^2.0.0"
+
+execa@^7.1.1:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9"
+ integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.1"
+ human-signals "^4.3.0"
+ is-stream "^3.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^5.1.0"
+ onetime "^6.0.0"
+ signal-exit "^3.0.7"
+ strip-final-newline "^3.0.0"
+
+exit@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
+ integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==
+
+expect@^29.0.0, expect@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc"
+ integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==
+ dependencies:
+ "@jest/expect-utils" "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+
+express@4.18.2:
+ version "4.18.2"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
+ integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
+ dependencies:
+ accepts "~1.3.8"
+ array-flatten "1.1.1"
+ body-parser "1.20.1"
+ content-disposition "0.5.4"
+ content-type "~1.0.4"
+ cookie "0.5.0"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "2.0.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "1.2.0"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ merge-descriptors "1.0.1"
+ methods "~1.1.2"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ path-to-regexp "0.1.7"
+ proxy-addr "~2.0.7"
+ qs "6.11.0"
+ range-parser "~1.2.1"
+ safe-buffer "5.2.1"
+ send "0.18.0"
+ serve-static "1.15.0"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ type-is "~1.6.18"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
+external-editor@^3.0.3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+ integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
+ dependencies:
+ chardet "^0.7.0"
+ iconv-lite "^0.4.24"
+ tmp "^0.0.33"
+
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-diff@^1.1.2:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0"
+ integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
+
+fast-glob@^3.2.9, fast-glob@^3.3.0:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-levenshtein@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+
+fast-safe-stringify@2.1.1, fast-safe-stringify@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
+ integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
+
+fastq@^1.6.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
+ integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
+ dependencies:
+ reusify "^1.0.4"
+
+fb-watchman@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c"
+ integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==
+ dependencies:
+ bser "2.1.1"
+
+fecha@^4.2.0:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd"
+ integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==
+
+figures@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
+ integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
+ dependencies:
+ escape-string-regexp "^1.0.5"
+
+file-entry-cache@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
+ integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
+ dependencies:
+ flat-cache "^3.0.4"
+
+file-stream-rotator@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz#007019e735b262bb6c6f0197e58e5c87cb96cec3"
+ integrity sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==
+ dependencies:
+ moment "^2.29.1"
+
+fill-range@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+ integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+finalhandler@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
+ integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ statuses "2.0.1"
+ unpipe "~1.0.0"
+
+find-up@^4.0.0, find-up@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+ dependencies:
+ locate-path "^5.0.0"
+ path-exists "^4.0.0"
+
+find-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
+flat-cache@^3.0.4:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b"
+ integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==
+ dependencies:
+ flatted "^3.2.9"
+ keyv "^4.5.3"
+ rimraf "^3.0.2"
+
+flatted@^3.2.9:
+ version "3.2.9"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf"
+ integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==
+
+fn.name@1.x.x:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
+ integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
+
+follow-redirects@^1.15.0:
+ version "1.15.3"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
+ integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
+
+foreground-child@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d"
+ integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==
+ dependencies:
+ cross-spawn "^7.0.0"
+ signal-exit "^4.0.1"
+
+fork-ts-checker-webpack-plugin@9.0.2:
+ version "9.0.2"
+ resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz#c12c590957837eb02b02916902dcf3e675fd2b1e"
+ integrity sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==
+ dependencies:
+ "@babel/code-frame" "^7.16.7"
+ chalk "^4.1.2"
+ chokidar "^3.5.3"
+ cosmiconfig "^8.2.0"
+ deepmerge "^4.2.2"
+ fs-extra "^10.0.0"
+ memfs "^3.4.1"
+ minimatch "^3.0.4"
+ node-abort-controller "^3.0.1"
+ schema-utils "^3.1.1"
+ semver "^7.3.5"
+ tapable "^2.2.1"
+
+form-data@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
+formidable@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.1.2.tgz#fa973a2bec150e4ce7cac15589d7a25fc30ebd89"
+ integrity sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==
+ dependencies:
+ dezalgo "^1.0.4"
+ hexoid "^1.0.0"
+ once "^1.4.0"
+ qs "^6.11.0"
+
+forwarded@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
+ integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
+
+fs-extra@^10.0.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
+ integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
+fs-monkey@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.5.tgz#fe450175f0db0d7ea758102e1d84096acb925788"
+ integrity sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+fsevents@^2.3.2, fsevents@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+generic-pool@3.9.0:
+ version "3.9.0"
+ resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4"
+ integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==
+
+gensync@^1.0.0-beta.2:
+ version "1.0.0-beta.2"
+ resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
+ integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
+
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b"
+ integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==
+ dependencies:
+ function-bind "^1.1.2"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ hasown "^2.0.0"
+
+get-package-type@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
+ integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+
+get-stream@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+ integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
+ dependencies:
+ pump "^3.0.0"
+
+get-stream@^6.0.0, get-stream@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+ integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
+glob-parent@^5.1.2, glob-parent@~5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob-parent@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+ integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
+ dependencies:
+ is-glob "^4.0.3"
+
+glob-to-regexp@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
+ integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
+
+glob@10.3.10:
+ version "10.3.10"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b"
+ integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==
+ dependencies:
+ foreground-child "^3.1.0"
+ jackspeak "^2.3.5"
+ minimatch "^9.0.1"
+ minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
+ path-scurry "^1.10.1"
+
+glob@^7.0.0, glob@^7.1.3, glob@^7.1.4:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.1.1"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
+ integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^5.0.1"
+ once "^1.3.0"
+
+glob@^9.2.0:
+ version "9.3.5"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21"
+ integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ minimatch "^8.0.2"
+ minipass "^4.2.4"
+ path-scurry "^1.6.1"
+
+globals@^11.1.0:
+ version "11.12.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globals@^13.19.0:
+ version "13.23.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02"
+ integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==
+ dependencies:
+ type-fest "^0.20.2"
+
+globby@^11.1.0:
+ version "11.1.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
+ integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
+ dependencies:
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.2.9"
+ ignore "^5.2.0"
+ merge2 "^1.4.1"
+ slash "^3.0.0"
+
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+graphemer@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
+ integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+has-flag@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+has-own-prop@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af"
+ integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==
+
+has-property-descriptors@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340"
+ integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==
+ dependencies:
+ get-intrinsic "^1.2.2"
+
+has-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
+ integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
+
+has-symbols@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+hasown@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c"
+ integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==
+ dependencies:
+ function-bind "^1.1.2"
+
+hexoid@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
+ integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==
+
+highlight.js@^10.7.1:
+ version "10.7.3"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
+ integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
+
+html-escaper@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
+ integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+
+http-errors@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+ integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+ dependencies:
+ depd "2.0.0"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ toidentifier "1.0.1"
+
+human-signals@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
+ integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
+
+human-signals@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+ integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
+human-signals@^4.3.0:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2"
+ integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==
+
+iconv-lite@0.4.24, iconv-lite@^0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+ieee754@^1.1.13, ieee754@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+ integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
+ignore@^5.2.0, ignore@^5.2.4:
+ version "5.2.4"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
+ integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
+
+import-fresh@^3.2.1, import-fresh@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+ integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
+import-local@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4"
+ integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==
+ dependencies:
+ pkg-dir "^4.2.0"
+ resolve-cwd "^3.0.0"
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inquirer@8.2.4:
+ version "8.2.4"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.4.tgz#ddbfe86ca2f67649a67daa6f1051c128f684f0b4"
+ integrity sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ chalk "^4.1.1"
+ cli-cursor "^3.1.0"
+ cli-width "^3.0.0"
+ external-editor "^3.0.3"
+ figures "^3.0.0"
+ lodash "^4.17.21"
+ mute-stream "0.0.8"
+ ora "^5.4.1"
+ run-async "^2.4.0"
+ rxjs "^7.5.5"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+ through "^2.3.6"
+ wrap-ansi "^7.0.0"
+
+inquirer@8.2.6:
+ version "8.2.6"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.6.tgz#733b74888195d8d400a67ac332011b5fae5ea562"
+ integrity sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ chalk "^4.1.1"
+ cli-cursor "^3.1.0"
+ cli-width "^3.0.0"
+ external-editor "^3.0.3"
+ figures "^3.0.0"
+ lodash "^4.17.21"
+ mute-stream "0.0.8"
+ ora "^5.4.1"
+ run-async "^2.4.0"
+ rxjs "^7.5.5"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+ through "^2.3.6"
+ wrap-ansi "^6.0.1"
+
+interpret@^1.0.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+ integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
+
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+ integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
+is-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.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
+is-core-module@^2.13.0:
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
+ integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
+ dependencies:
+ hasown "^2.0.0"
+
+is-docker@^2.0.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
+ integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
+
+is-docker@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200"
+ integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-generator-fn@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118"
+ integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
+
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-inside-container@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4"
+ integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==
+ dependencies:
+ is-docker "^3.0.0"
+
+is-interactive@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
+ integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-path-inside@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+is-stream@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
+is-stream@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac"
+ integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==
+
+is-unicode-supported@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
+ integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
+
+is-wsl@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
+ integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
+ dependencies:
+ is-docker "^2.0.0"
+
+isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756"
+ integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==
+
+istanbul-lib-instrument@^5.0.4:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d"
+ integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==
+ dependencies:
+ "@babel/core" "^7.12.3"
+ "@babel/parser" "^7.14.7"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-coverage "^3.2.0"
+ semver "^6.3.0"
+
+istanbul-lib-instrument@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz#71e87707e8041428732518c6fb5211761753fbdf"
+ integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==
+ dependencies:
+ "@babel/core" "^7.12.3"
+ "@babel/parser" "^7.14.7"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-coverage "^3.2.0"
+ semver "^7.5.4"
+
+istanbul-lib-report@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d"
+ integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==
+ dependencies:
+ istanbul-lib-coverage "^3.0.0"
+ make-dir "^4.0.0"
+ supports-color "^7.1.0"
+
+istanbul-lib-source-maps@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551"
+ integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==
+ dependencies:
+ debug "^4.1.1"
+ istanbul-lib-coverage "^3.0.0"
+ source-map "^0.6.1"
+
+istanbul-reports@^3.1.3:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a"
+ integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==
+ dependencies:
+ html-escaper "^2.0.0"
+ istanbul-lib-report "^3.0.0"
+
+iterare@1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/iterare/-/iterare-1.2.1.tgz#139c400ff7363690e33abffa33cbba8920f00042"
+ integrity sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==
+
+jackspeak@^2.3.5:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
+ integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
+ dependencies:
+ "@isaacs/cliui" "^8.0.2"
+ optionalDependencies:
+ "@pkgjs/parseargs" "^0.11.0"
+
+jest-changed-files@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a"
+ integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==
+ dependencies:
+ execa "^5.0.0"
+ jest-util "^29.7.0"
+ p-limit "^3.1.0"
+
+jest-circus@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a"
+ integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/expect" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ co "^4.6.0"
+ dedent "^1.0.0"
+ is-generator-fn "^2.0.0"
+ jest-each "^29.7.0"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-runtime "^29.7.0"
+ jest-snapshot "^29.7.0"
+ jest-util "^29.7.0"
+ p-limit "^3.1.0"
+ pretty-format "^29.7.0"
+ pure-rand "^6.0.0"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+
+jest-cli@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995"
+ integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==
+ dependencies:
+ "@jest/core" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ chalk "^4.0.0"
+ create-jest "^29.7.0"
+ exit "^0.1.2"
+ import-local "^3.0.2"
+ jest-config "^29.7.0"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
+ yargs "^17.3.1"
+
+jest-config@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f"
+ integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==
+ dependencies:
+ "@babel/core" "^7.11.6"
+ "@jest/test-sequencer" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ babel-jest "^29.7.0"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ deepmerge "^4.2.2"
+ glob "^7.1.3"
+ graceful-fs "^4.2.9"
+ jest-circus "^29.7.0"
+ jest-environment-node "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-regex-util "^29.6.3"
+ jest-resolve "^29.7.0"
+ jest-runner "^29.7.0"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
+ micromatch "^4.0.4"
+ parse-json "^5.2.0"
+ pretty-format "^29.7.0"
+ slash "^3.0.0"
+ strip-json-comments "^3.1.1"
+
+jest-diff@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a"
+ integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==
+ dependencies:
+ chalk "^4.0.0"
+ diff-sequences "^29.6.3"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
+jest-docblock@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a"
+ integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==
+ dependencies:
+ detect-newline "^3.0.0"
+
+jest-each@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1"
+ integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ chalk "^4.0.0"
+ jest-get-type "^29.6.3"
+ jest-util "^29.7.0"
+ pretty-format "^29.7.0"
+
+jest-environment-node@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376"
+ integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/fake-timers" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ jest-mock "^29.7.0"
+ jest-util "^29.7.0"
+
+jest-get-type@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1"
+ integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==
+
+jest-haste-map@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104"
+ integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/graceful-fs" "^4.1.3"
+ "@types/node" "*"
+ anymatch "^3.0.3"
+ fb-watchman "^2.0.0"
+ graceful-fs "^4.2.9"
+ jest-regex-util "^29.6.3"
+ jest-util "^29.7.0"
+ jest-worker "^29.7.0"
+ micromatch "^4.0.4"
+ walker "^1.0.8"
+ optionalDependencies:
+ fsevents "^2.3.2"
+
+jest-leak-detector@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728"
+ integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==
+ dependencies:
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
+jest-matcher-utils@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12"
+ integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==
+ dependencies:
+ chalk "^4.0.0"
+ jest-diff "^29.7.0"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
+jest-message-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3"
+ integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@jest/types" "^29.6.3"
+ "@types/stack-utils" "^2.0.0"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ micromatch "^4.0.4"
+ pretty-format "^29.7.0"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+
+jest-mock@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347"
+ integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ jest-util "^29.7.0"
+
+jest-pnp-resolver@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e"
+ integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==
+
+jest-regex-util@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52"
+ integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==
+
+jest-resolve-dependencies@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428"
+ integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==
+ dependencies:
+ jest-regex-util "^29.6.3"
+ jest-snapshot "^29.7.0"
+
+jest-resolve@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30"
+ integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==
+ dependencies:
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^29.7.0"
+ jest-pnp-resolver "^1.2.2"
+ jest-util "^29.7.0"
+ jest-validate "^29.7.0"
+ resolve "^1.20.0"
+ resolve.exports "^2.0.0"
+ slash "^3.0.0"
+
+jest-runner@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e"
+ integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==
+ dependencies:
+ "@jest/console" "^29.7.0"
+ "@jest/environment" "^29.7.0"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ emittery "^0.13.1"
+ graceful-fs "^4.2.9"
+ jest-docblock "^29.7.0"
+ jest-environment-node "^29.7.0"
+ jest-haste-map "^29.7.0"
+ jest-leak-detector "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-resolve "^29.7.0"
+ jest-runtime "^29.7.0"
+ jest-util "^29.7.0"
+ jest-watcher "^29.7.0"
+ jest-worker "^29.7.0"
+ p-limit "^3.1.0"
+ source-map-support "0.5.13"
+
+jest-runtime@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817"
+ integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==
+ dependencies:
+ "@jest/environment" "^29.7.0"
+ "@jest/fake-timers" "^29.7.0"
+ "@jest/globals" "^29.7.0"
+ "@jest/source-map" "^29.6.3"
+ "@jest/test-result" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ cjs-module-lexer "^1.0.0"
+ collect-v8-coverage "^1.0.0"
+ glob "^7.1.3"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-mock "^29.7.0"
+ jest-regex-util "^29.6.3"
+ jest-resolve "^29.7.0"
+ jest-snapshot "^29.7.0"
+ jest-util "^29.7.0"
+ slash "^3.0.0"
+ strip-bom "^4.0.0"
+
+jest-snapshot@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5"
+ integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==
+ dependencies:
+ "@babel/core" "^7.11.6"
+ "@babel/generator" "^7.7.2"
+ "@babel/plugin-syntax-jsx" "^7.7.2"
+ "@babel/plugin-syntax-typescript" "^7.7.2"
+ "@babel/types" "^7.3.3"
+ "@jest/expect-utils" "^29.7.0"
+ "@jest/transform" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ babel-preset-current-node-syntax "^1.0.0"
+ chalk "^4.0.0"
+ expect "^29.7.0"
+ graceful-fs "^4.2.9"
+ jest-diff "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+ natural-compare "^1.4.0"
+ pretty-format "^29.7.0"
+ semver "^7.5.3"
+
+jest-util@^29.0.0, jest-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc"
+ integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ graceful-fs "^4.2.9"
+ picomatch "^2.2.3"
+
+jest-validate@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c"
+ integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ camelcase "^6.2.0"
+ chalk "^4.0.0"
+ jest-get-type "^29.6.3"
+ leven "^3.1.0"
+ pretty-format "^29.7.0"
+
+jest-watcher@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2"
+ integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==
+ dependencies:
+ "@jest/test-result" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ ansi-escapes "^4.2.1"
+ chalk "^4.0.0"
+ emittery "^0.13.1"
+ jest-util "^29.7.0"
+ string-length "^4.0.1"
+
+jest-worker@^27.4.5:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
+ integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==
+ dependencies:
+ "@types/node" "*"
+ merge-stream "^2.0.0"
+ supports-color "^8.0.0"
+
+jest-worker@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a"
+ integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==
+ dependencies:
+ "@types/node" "*"
+ jest-util "^29.7.0"
+ merge-stream "^2.0.0"
+ supports-color "^8.0.0"
+
+jest@^29.5.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613"
+ integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==
+ dependencies:
+ "@jest/core" "^29.7.0"
+ "@jest/types" "^29.6.3"
+ import-local "^3.0.2"
+ jest-cli "^29.7.0"
+
+jose@^1.15.0:
+ version "1.28.2"
+ resolved "https://registry.yarnpkg.com/jose/-/jose-1.28.2.tgz#97f4aa608d0020ae5c1051a2a33247b957401e5a"
+ integrity sha512-wWy51U2MXxYi3g8zk2lsQ8M6O1lartpkxuq1TYexzPKYLgHLZkCjklaATP36I5BUoWjF2sInB9U1Qf18fBZxNA==
+ dependencies:
+ "@panva/asn1.js" "^1.0.0"
+
+js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@^3.13.1:
+ version "3.14.1"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
+ integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
+js-yaml@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+ integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+ dependencies:
+ argparse "^2.0.1"
+
+jsesc@^2.5.1:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+ integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
+json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+
+json5@^2.2.2, json5@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
+ integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+
+jsonc-parser@3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76"
+ integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==
+
+jsonfile@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+ integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+ dependencies:
+ universalify "^2.0.0"
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+jsonwebtoken@9.0.2:
+ version "9.0.2"
+ resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3"
+ integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==
+ dependencies:
+ jws "^3.2.2"
+ lodash.includes "^4.3.0"
+ lodash.isboolean "^3.0.3"
+ lodash.isinteger "^4.0.4"
+ lodash.isnumber "^3.0.3"
+ lodash.isplainobject "^4.0.6"
+ lodash.isstring "^4.0.1"
+ lodash.once "^4.0.0"
+ ms "^2.1.1"
+ semver "^7.5.4"
+
+jwa@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
+ integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
+ dependencies:
+ buffer-equal-constant-time "1.0.1"
+ ecdsa-sig-formatter "1.0.11"
+ safe-buffer "^5.0.1"
+
+jws@^3.2.2:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
+ integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
+ dependencies:
+ jwa "^1.4.1"
+ safe-buffer "^5.0.1"
+
+keyv@^4.5.3:
+ version "4.5.4"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
+ integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
+ dependencies:
+ json-buffer "3.0.1"
+
+kleur@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
+ integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
+
+kuler@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
+ integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
+
+leven@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
+ integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
+
+levn@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+ integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
+ dependencies:
+ prelude-ls "^1.2.1"
+ type-check "~0.4.0"
+
+libphonenumber-js@^1.10.14:
+ version "1.10.49"
+ resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.49.tgz#c871661c62452348d228c96425f75ddf7e10f05a"
+ integrity sha512-gvLtyC3tIuqfPzjvYLH9BmVdqzGDiSi4VjtWe2fAgSdBf0yt8yPmbNnRIHNbR5IdtVkm0ayGuzwQKTWmU0hdjQ==
+
+lines-and-columns@^1.1.6:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+ integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
+loader-runner@^4.2.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
+ integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
+
+locate-path@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+ dependencies:
+ p-locate "^4.1.0"
+
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
+
+lodash.includes@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
+ integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==
+
+lodash.isboolean@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
+ integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==
+
+lodash.isinteger@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
+ integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==
+
+lodash.isnumber@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
+ integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==
+
+lodash.isplainobject@^4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+ integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==
+
+lodash.isstring@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
+ integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==
+
+lodash.memoize@4.x:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
+ integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
+
+lodash.merge@^4.6.2:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+ integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
+lodash.once@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
+ integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==
+
+lodash@4.17.21, lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+log-symbols@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
+ integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
+ dependencies:
+ chalk "^4.1.0"
+ is-unicode-supported "^0.1.0"
+
+logform@^2.3.2, logform@^2.4.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.0.tgz#8c82a983f05d6eaeb2d75e3decae7a768b2bf9b5"
+ integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==
+ dependencies:
+ "@colors/colors" "1.6.0"
+ "@types/triple-beam" "^1.3.2"
+ fecha "^4.2.0"
+ ms "^2.1.1"
+ safe-stable-stringify "^2.3.1"
+ triple-beam "^1.3.0"
+
+lru-cache@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
+ integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+ dependencies:
+ yallist "^3.0.2"
+
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
+"lru-cache@^9.1.1 || ^10.0.0":
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a"
+ integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==
+
+macos-release@^2.5.0:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.5.1.tgz#bccac4a8f7b93163a8d163b8ebf385b3c5f55bf9"
+ integrity sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==
+
+magic-string@0.30.1:
+ version "0.30.1"
+ resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.1.tgz#ce5cd4b0a81a5d032bd69aab4522299b2166284d"
+ integrity sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.4.15"
+
+make-dir@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e"
+ integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==
+ dependencies:
+ semver "^7.5.3"
+
+make-error@1.x, make-error@^1.1.1:
+ version "1.3.6"
+ resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
+ integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
+
+makeerror@1.0.12:
+ version "1.0.12"
+ resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a"
+ integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==
+ dependencies:
+ tmpl "1.0.5"
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
+
+memfs@^3.4.1:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6"
+ integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ==
+ dependencies:
+ fs-monkey "^1.0.4"
+
+merge-descriptors@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+ integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==
+
+merge-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+ integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+merge2@^1.3.0, merge2@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+methods@^1.1.2, methods@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
+
+micromatch@^4.0.0, micromatch@^4.0.4:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+ integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+ dependencies:
+ braces "^3.0.2"
+ picomatch "^2.3.1"
+
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+mime@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+mime@2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
+ integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
+
+mimic-fn@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+mimic-fn@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
+ integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==
+
+minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimatch@^5.0.1:
+ version "5.1.6"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
+ integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimatch@^8.0.2:
+ version "8.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229"
+ integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimatch@^9.0.1:
+ version "9.0.3"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
+ integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimist@^1.2.6:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+ integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+minipass@^4.2.4:
+ version "4.2.8"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a"
+ integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==
+
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0":
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
+ integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
+
+mkdirp@^0.5.4:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
+ integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
+ dependencies:
+ minimist "^1.2.6"
+
+mkdirp@^2.1.3:
+ version "2.1.6"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19"
+ integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==
+
+moment@^2.29.1:
+ version "2.29.4"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
+ integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+
+ms@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+ms@2.1.3, ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+multer@1.4.4-lts.1:
+ version "1.4.4-lts.1"
+ resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.4-lts.1.tgz#24100f701a4611211cfae94ae16ea39bb314e04d"
+ integrity sha512-WeSGziVj6+Z2/MwQo3GvqzgR+9Uc+qt8SwHKh3gvNPiISKfsMfG4SvCOFYlxxgkXt7yIV2i1yczehm0EOKIxIg==
+ dependencies:
+ append-field "^1.0.0"
+ busboy "^1.0.0"
+ concat-stream "^1.5.2"
+ mkdirp "^0.5.4"
+ object-assign "^4.1.1"
+ type-is "^1.6.4"
+ xtend "^4.0.0"
+
+mute-stream@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
+ integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
+
+mz@^2.4.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+ integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+ dependencies:
+ any-promise "^1.0.0"
+ object-assign "^4.0.1"
+ thenify-all "^1.0.0"
+
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
+neo-async@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
+ integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+
+nest-winston@^1.9.4:
+ version "1.9.4"
+ resolved "https://registry.yarnpkg.com/nest-winston/-/nest-winston-1.9.4.tgz#1cc53a2087818bc89663cbaa0bf65061d6b81c6f"
+ integrity sha512-ilEmHuuYSAI6aMNR120fLBl42EdY13QI9WRggHdEizt9M7qZlmXJwpbemVWKW/tqRmULjSx/otKNQ3GMQbfoUQ==
+ dependencies:
+ fast-safe-stringify "^2.1.1"
+
+node-abort-controller@^3.0.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548"
+ integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==
+
+node-emoji@1.11.0:
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c"
+ integrity sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==
+ dependencies:
+ lodash "^4.17.21"
+
+node-fetch@^2.6.1:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
+ integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
+ dependencies:
+ whatwg-url "^5.0.0"
+
+node-int64@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+ integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
+
+node-releases@^2.0.13:
+ version "2.0.13"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d"
+ integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+npm-run-path@^4.0.0, npm-run-path@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
+npm-run-path@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00"
+ integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==
+ dependencies:
+ path-key "^4.0.0"
+
+object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+object-hash@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
+ integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
+
+object-hash@^2.0.1:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5"
+ integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
+
+object-inspect@^1.9.0:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
+ integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
+
+on-finished@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+ integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+ dependencies:
+ ee-first "1.1.1"
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+one-time@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45"
+ integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==
+ dependencies:
+ fn.name "1.x.x"
+
+onetime@^5.1.0, onetime@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+ integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+ dependencies:
+ mimic-fn "^2.1.0"
+
+onetime@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4"
+ integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==
+ dependencies:
+ mimic-fn "^4.0.0"
+
+open@^9.1.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6"
+ integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==
+ dependencies:
+ default-browser "^4.0.0"
+ define-lazy-prop "^3.0.0"
+ is-inside-container "^1.0.0"
+ is-wsl "^2.2.0"
+
+optionator@^0.9.3:
+ version "0.9.3"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64"
+ integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==
+ dependencies:
+ "@aashutoshrathi/word-wrap" "^1.2.3"
+ deep-is "^0.1.3"
+ fast-levenshtein "^2.0.6"
+ levn "^0.4.1"
+ prelude-ls "^1.2.1"
+ type-check "^0.4.0"
+
+ora@5.4.1, ora@^5.4.1:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
+ integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==
+ dependencies:
+ bl "^4.1.0"
+ chalk "^4.1.0"
+ cli-cursor "^3.1.0"
+ cli-spinners "^2.5.0"
+ is-interactive "^1.0.0"
+ is-unicode-supported "^0.1.0"
+ log-symbols "^4.1.0"
+ strip-ansi "^6.0.0"
+ wcwidth "^1.0.1"
+
+os-name@4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/os-name/-/os-name-4.0.1.tgz#32cee7823de85a8897647ba4d76db46bf845e555"
+ integrity sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==
+ dependencies:
+ macos-release "^2.5.0"
+ windows-release "^4.0.0"
+
+os-tmpdir@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+ integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
+
+p-limit@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+ dependencies:
+ p-try "^2.0.0"
+
+p-limit@^3.0.2, p-limit@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+ dependencies:
+ yocto-queue "^0.1.0"
+
+p-locate@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+ dependencies:
+ p-limit "^2.2.0"
+
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
+
+p-try@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+packet-reader@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74"
+ integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
+
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
+parse-json@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ error-ex "^1.3.1"
+ json-parse-even-better-errors "^2.3.0"
+ lines-and-columns "^1.1.6"
+
+parse5-htmlparser2-tree-adapter@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
+ integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==
+ dependencies:
+ parse5 "^6.0.1"
+
+parse5@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
+ integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
+
+parse5@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
+ integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
+
+parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-key@^3.0.0, path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-key@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18"
+ integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==
+
+path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-scurry@^1.10.1, path-scurry@^1.6.1:
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698"
+ integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==
+ dependencies:
+ lru-cache "^9.1.1 || ^10.0.0"
+ minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
+
+path-to-regexp@0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+ integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
+
+path-to-regexp@3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.2.0.tgz#fa7877ecbc495c601907562222453c43cc204a5f"
+ integrity sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==
+
+path-type@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+pg-cloudflare@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98"
+ integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==
+
+pg-connection-string@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.2.tgz#713d82053de4e2bd166fab70cd4f26ad36aab475"
+ integrity sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==
+
+pg-int8@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c"
+ integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==
+
+pg-pool@^3.6.1:
+ version "3.6.1"
+ resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.1.tgz#5a902eda79a8d7e3c928b77abf776b3cb7d351f7"
+ integrity sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==
+
+pg-protocol@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.0.tgz#4c91613c0315349363af2084608db843502f8833"
+ integrity sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==
+
+pg-types@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3"
+ integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==
+ dependencies:
+ pg-int8 "1.0.1"
+ postgres-array "~2.0.0"
+ postgres-bytea "~1.0.0"
+ postgres-date "~1.0.4"
+ postgres-interval "^1.1.0"
+
+pg@^8.11.3:
+ version "8.11.3"
+ resolved "https://registry.yarnpkg.com/pg/-/pg-8.11.3.tgz#d7db6e3fe268fcedd65b8e4599cda0b8b4bf76cb"
+ integrity sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==
+ dependencies:
+ buffer-writer "2.0.0"
+ packet-reader "1.0.0"
+ pg-connection-string "^2.6.2"
+ pg-pool "^3.6.1"
+ pg-protocol "^1.6.0"
+ pg-types "^2.1.0"
+ pgpass "1.x"
+ optionalDependencies:
+ pg-cloudflare "^1.1.1"
+
+pgpass@1.x:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d"
+ integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==
+ dependencies:
+ split2 "^4.1.0"
+
+picocolors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+ integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@2.3.1, picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pirates@^4.0.4:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
+ integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==
+
+pkg-dir@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
+ integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
+ dependencies:
+ find-up "^4.0.0"
+
+pluralize@8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
+ integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
+
+postgres-array@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e"
+ integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==
+
+postgres-bytea@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35"
+ integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==
+
+postgres-date@~1.0.4:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8"
+ integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==
+
+postgres-interval@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695"
+ integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==
+ dependencies:
+ xtend "^4.0.0"
+
+prelude-ls@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+ integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+
+prettier-linter-helpers@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
+ integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
+ dependencies:
+ fast-diff "^1.1.2"
+
+prettier@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643"
+ integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==
+
+pretty-format@^29.0.0, pretty-format@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
+ integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
+process-nextick-args@~2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+ integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+prompts@^2.0.1:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
+ integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
+ dependencies:
+ kleur "^3.0.3"
+ sisteransi "^1.0.5"
+
+proxy-addr@~2.0.7:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
+ integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
+ dependencies:
+ forwarded "0.2.0"
+ ipaddr.js "1.9.1"
+
+proxy-from-env@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+ integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
+pump@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+punycode@^2.1.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+
+pure-rand@^6.0.0:
+ version "6.0.4"
+ resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7"
+ integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==
+
+qs@6.11.0:
+ version "6.11.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
+ integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
+ dependencies:
+ side-channel "^1.0.4"
+
+qs@^6.11.0:
+ version "6.11.2"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
+ integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==
+ dependencies:
+ side-channel "^1.0.4"
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+randombytes@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+ dependencies:
+ safe-buffer "^5.1.0"
+
+range-parser@~1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
+ integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+raw-body@2.5.2:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+ integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+react-is@^18.0.0:
+ version "18.2.0"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
+ integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
+
+readable-stream@^2.2.2:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
+ integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readable-stream@^3.4.0, readable-stream@^3.6.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+ integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+ dependencies:
+ picomatch "^2.2.1"
+
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==
+ dependencies:
+ resolve "^1.1.6"
+
+redis@^4.6.11:
+ version "4.6.11"
+ resolved "https://registry.yarnpkg.com/redis/-/redis-4.6.11.tgz#fad85e104545228f212259fd557c3e4f8eafcd3d"
+ integrity sha512-kg1Lt4NZLYkAjPOj/WcyIGWfZfnyfKo1Wg9YKVSlzhFwxpFIl3LYI8BWy1Ab963LLDsTz2+OwdsesHKljB3WMQ==
+ dependencies:
+ "@redis/bloom" "1.2.0"
+ "@redis/client" "1.5.12"
+ "@redis/graph" "1.1.1"
+ "@redis/json" "1.0.6"
+ "@redis/search" "1.1.6"
+ "@redis/time-series" "1.0.5"
+
+reflect-metadata@^0.1.13:
+ version "0.1.13"
+ resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
+ integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
+
+regenerator-runtime@^0.14.0:
+ version "0.14.0"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
+ integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
+
+repeat-string@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+ integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+require-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
+resolve-cwd@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
+ integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
+ dependencies:
+ resolve-from "^5.0.0"
+
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve-from@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
+resolve.exports@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800"
+ integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==
+
+resolve@^1.1.6, resolve@^1.20.0:
+ version "1.22.8"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
+ integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
+ dependencies:
+ is-core-module "^2.13.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+restore-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+ integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
+ dependencies:
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rimraf@4.4.1:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.1.tgz#bd33364f67021c5b79e93d7f4fa0568c7c21b755"
+ integrity sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==
+ dependencies:
+ glob "^9.2.0"
+
+rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
+run-applescript@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c"
+ integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==
+ dependencies:
+ execa "^5.0.0"
+
+run-async@^2.4.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
+ integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+rxjs@7.8.1, rxjs@^7.5.5, rxjs@^7.8.1:
+ version "7.8.1"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
+ integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
+ dependencies:
+ tslib "^2.1.0"
+
+safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-stable-stringify@^2.3.1:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886"
+ integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==
+
+"safer-buffer@>= 2.1.2 < 3":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+schema-utils@^3.1.1, schema-utils@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
+ integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
+ dependencies:
+ "@types/json-schema" "^7.0.8"
+ ajv "^6.12.5"
+ ajv-keywords "^3.5.2"
+
+semver@^6.3.0, semver@^6.3.1:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
+semver@^7.3.4, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4:
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+ dependencies:
+ lru-cache "^6.0.0"
+
+send@0.18.0:
+ version "0.18.0"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
+ integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
+ dependencies:
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ mime "1.6.0"
+ ms "2.1.3"
+ on-finished "2.4.1"
+ range-parser "~1.2.1"
+ statuses "2.0.1"
+
+serialize-javascript@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c"
+ integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==
+ dependencies:
+ randombytes "^2.1.0"
+
+serve-static@1.15.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
+ integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
+ dependencies:
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ parseurl "~1.3.3"
+ send "0.18.0"
+
+set-function-length@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed"
+ integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==
+ dependencies:
+ define-data-property "^1.1.1"
+ get-intrinsic "^1.2.1"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.0"
+
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
+sha.js@^2.4.11:
+ version "2.4.11"
+ resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
+ integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+shelljs@0.8.5:
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
+ integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
+ dependencies:
+ glob "^7.0.0"
+ interpret "^1.0.0"
+ rechoir "^0.6.2"
+
+side-channel@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
+ integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
+ dependencies:
+ call-bind "^1.0.0"
+ get-intrinsic "^1.0.2"
+ object-inspect "^1.9.0"
+
+signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+ integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
+signal-exit@^4.0.1:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
+ integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
+
+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.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
+ integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
+
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+source-map-support@0.5.13:
+ version "0.5.13"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
+ integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
+source-map-support@0.5.21, source-map-support@^0.5.21, source-map-support@~0.5.20:
+ version "0.5.21"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
+ integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
+source-map@0.7.4, source-map@^0.7.4:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
+ integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
+
+source-map@^0.6.0, source-map@^0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+split2@^4.1.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4"
+ integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+
+stack-trace@0.0.x:
+ version "0.0.10"
+ resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
+ integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==
+
+stack-utils@^2.0.3:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f"
+ integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==
+ dependencies:
+ escape-string-regexp "^2.0.0"
+
+statuses@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+ integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+streamsearch@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
+ integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
+
+string-length@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
+ integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==
+ dependencies:
+ char-regex "^1.0.2"
+ strip-ansi "^6.0.0"
+
+"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^5.0.1, string-width@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
+ integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
+ dependencies:
+ eastasianwidth "^0.2.0"
+ emoji-regex "^9.2.2"
+ strip-ansi "^7.0.1"
+
+string_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+ dependencies:
+ safe-buffer "~5.2.0"
+
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-ansi@^7.0.1:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
+ integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
+ dependencies:
+ ansi-regex "^6.0.1"
+
+strip-bom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+ integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
+
+strip-bom@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878"
+ integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
+
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
+strip-final-newline@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd"
+ integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==
+
+strip-json-comments@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
+superagent@^8.0.5:
+ version "8.1.2"
+ resolved "https://registry.yarnpkg.com/superagent/-/superagent-8.1.2.tgz#03cb7da3ec8b32472c9d20f6c2a57c7f3765f30b"
+ integrity sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==
+ dependencies:
+ component-emitter "^1.3.0"
+ cookiejar "^2.1.4"
+ debug "^4.3.4"
+ fast-safe-stringify "^2.1.1"
+ form-data "^4.0.0"
+ formidable "^2.1.2"
+ methods "^1.1.2"
+ mime "2.6.0"
+ qs "^6.11.0"
+ semver "^7.3.8"
+
+supertest@^6.3.3:
+ version "6.3.3"
+ resolved "https://registry.yarnpkg.com/supertest/-/supertest-6.3.3.tgz#42f4da199fee656106fd422c094cf6c9578141db"
+ integrity sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==
+ dependencies:
+ methods "^1.1.2"
+ superagent "^8.0.5"
+
+supports-color@^5.3.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^7.1.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-color@^8.0.0:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+ integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+symbol-observable@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205"
+ integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==
+
+synckit@^0.8.5:
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3"
+ integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==
+ dependencies:
+ "@pkgr/utils" "^2.3.1"
+ tslib "^2.5.0"
+
+tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+ integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+
+terser-webpack-plugin@^5.3.7:
+ version "5.3.9"
+ resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1"
+ integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.17"
+ jest-worker "^27.4.5"
+ schema-utils "^3.1.1"
+ serialize-javascript "^6.0.1"
+ terser "^5.16.8"
+
+terser@^5.16.8:
+ version "5.24.0"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.24.0.tgz#4ae50302977bca4831ccc7b4fef63a3c04228364"
+ integrity sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==
+ dependencies:
+ "@jridgewell/source-map" "^0.3.3"
+ acorn "^8.8.2"
+ commander "^2.20.0"
+ source-map-support "~0.5.20"
+
+test-exclude@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
+ integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==
+ dependencies:
+ "@istanbuljs/schema" "^0.1.2"
+ glob "^7.1.4"
+ minimatch "^3.0.4"
+
+text-hex@1.0.x:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
+ integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
+
+text-table@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+
+thenify-all@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+ integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
+ dependencies:
+ thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+ integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
+ dependencies:
+ any-promise "^1.0.0"
+
+through@^2.3.6:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+ integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
+
+titleize@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53"
+ integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==
+
+tmp@^0.0.33:
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+ integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+ dependencies:
+ os-tmpdir "~1.0.2"
+
+tmpl@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
+ integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
+
+to-fast-properties@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+ integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
+tr46@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+ integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+
+tree-kill@1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
+ integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
+
+triple-beam@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984"
+ integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==
+
+ts-api-utils@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331"
+ integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==
+
+ts-jest@^29.1.0:
+ version "29.1.1"
+ resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b"
+ integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==
+ dependencies:
+ bs-logger "0.x"
+ fast-json-stable-stringify "2.x"
+ jest-util "^29.0.0"
+ json5 "^2.2.3"
+ lodash.memoize "4.x"
+ make-error "1.x"
+ semver "^7.5.3"
+ yargs-parser "^21.0.1"
+
+ts-loader@^9.4.3:
+ version "9.5.0"
+ resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.0.tgz#f0a51dda37cc4d8e43e6cb14edebbc599b0c3aa2"
+ integrity sha512-LLlB/pkB4q9mW2yLdFMnK3dEHbrBjeZTYguaaIfusyojBgAGf5kF+O6KcWqiGzWqHk0LBsoolrp4VftEURhybg==
+ dependencies:
+ chalk "^4.1.0"
+ enhanced-resolve "^5.0.0"
+ micromatch "^4.0.0"
+ semver "^7.3.4"
+ source-map "^0.7.4"
+
+ts-node@^10.9.1:
+ version "10.9.1"
+ resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
+ integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
+ dependencies:
+ "@cspotcode/source-map-support" "^0.8.0"
+ "@tsconfig/node10" "^1.0.7"
+ "@tsconfig/node12" "^1.0.7"
+ "@tsconfig/node14" "^1.0.0"
+ "@tsconfig/node16" "^1.0.2"
+ acorn "^8.4.1"
+ acorn-walk "^8.1.1"
+ arg "^4.1.0"
+ create-require "^1.1.0"
+ diff "^4.0.1"
+ make-error "^1.1.1"
+ v8-compile-cache-lib "^3.0.1"
+ yn "3.1.1"
+
+tsconfig-paths-webpack-plugin@4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz#3c6892c5e7319c146eee1e7302ed9e6f2be4f763"
+ integrity sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA==
+ dependencies:
+ chalk "^4.1.0"
+ enhanced-resolve "^5.7.0"
+ tsconfig-paths "^4.1.2"
+
+tsconfig-paths@4.2.0, tsconfig-paths@^4.1.2, tsconfig-paths@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c"
+ integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==
+ dependencies:
+ json5 "^2.2.2"
+ minimist "^1.2.6"
+ strip-bom "^3.0.0"
+
+tslib@2.6.2, tslib@^2.1.0, tslib@^2.5.0, tslib@^2.6.0:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
+ integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
+
+type-check@^0.4.0, type-check@~0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+ integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
+ dependencies:
+ prelude-ls "^1.2.1"
+
+type-detect@4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
+ integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+
+type-fest@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+ integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type-fest@^0.21.3:
+ version "0.21.3"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
+ integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
+
+type-is@^1.6.4, type-is@~1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
+typedarray@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+ integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
+
+typeorm@^0.3.17:
+ version "0.3.17"
+ resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.17.tgz#a73c121a52e4fbe419b596b244777be4e4b57949"
+ integrity sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig==
+ dependencies:
+ "@sqltools/formatter" "^1.2.5"
+ app-root-path "^3.1.0"
+ buffer "^6.0.3"
+ chalk "^4.1.2"
+ cli-highlight "^2.1.11"
+ date-fns "^2.29.3"
+ debug "^4.3.4"
+ dotenv "^16.0.3"
+ glob "^8.1.0"
+ mkdirp "^2.1.3"
+ reflect-metadata "^0.1.13"
+ sha.js "^2.4.11"
+ tslib "^2.5.0"
+ uuid "^9.0.0"
+ yargs "^17.6.2"
+
+typescript@5.2.2, typescript@^5.1.3:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
+ integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
+
+uid@2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/uid/-/uid-2.0.2.tgz#4b5782abf0f2feeefc00fa88006b2b3b7af3e3b9"
+ integrity sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==
+ dependencies:
+ "@lukeed/csprng" "^1.0.0"
+
+undici-types@~5.26.4:
+ version "5.26.5"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+ integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
+universalify@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
+ integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
+
+unpipe@1.0.0, unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
+untildify@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
+ integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
+
+update-browserslist-db@^1.0.13:
+ version "1.0.13"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
+ integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
+ dependencies:
+ escalade "^3.1.1"
+ picocolors "^1.0.0"
+
+uri-js@^4.2.2:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ dependencies:
+ punycode "^2.1.0"
+
+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
+uuid@9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
+ integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
+
+uuid@^9.0.0, uuid@^9.0.1:
+ version "9.0.1"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
+ integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
+
+v8-compile-cache-lib@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
+ integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
+
+v8-to-istanbul@^9.0.1:
+ version "9.1.3"
+ resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz#ea456604101cd18005ac2cae3cdd1aa058a6306b"
+ integrity sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.12"
+ "@types/istanbul-lib-coverage" "^2.0.1"
+ convert-source-map "^2.0.0"
+
+validator@^13.7.0:
+ version "13.11.0"
+ resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b"
+ integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==
+
+vary@^1, vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+
+walker@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f"
+ integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==
+ dependencies:
+ makeerror "1.0.12"
+
+watchpack@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
+ integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
+ dependencies:
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.1.2"
+
+wcwidth@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
+ integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==
+ dependencies:
+ defaults "^1.0.3"
+
+webidl-conversions@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+ integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
+
+webpack-node-externals@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz#1a3407c158d547a9feb4229a9e3385b7b60c9917"
+ integrity sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==
+
+webpack-sources@^3.2.3:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+ integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
+
+webpack@5.89.0:
+ version "5.89.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.89.0.tgz#56b8bf9a34356e93a6625770006490bf3a7f32dc"
+ integrity sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==
+ dependencies:
+ "@types/eslint-scope" "^3.7.3"
+ "@types/estree" "^1.0.0"
+ "@webassemblyjs/ast" "^1.11.5"
+ "@webassemblyjs/wasm-edit" "^1.11.5"
+ "@webassemblyjs/wasm-parser" "^1.11.5"
+ acorn "^8.7.1"
+ acorn-import-assertions "^1.9.0"
+ browserslist "^4.14.5"
+ chrome-trace-event "^1.0.2"
+ enhanced-resolve "^5.15.0"
+ es-module-lexer "^1.2.1"
+ eslint-scope "5.1.1"
+ events "^3.2.0"
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.2.9"
+ json-parse-even-better-errors "^2.3.1"
+ loader-runner "^4.2.0"
+ mime-types "^2.1.27"
+ neo-async "^2.6.2"
+ schema-utils "^3.2.0"
+ tapable "^2.1.1"
+ terser-webpack-plugin "^5.3.7"
+ watchpack "^2.4.0"
+ webpack-sources "^3.2.3"
+
+whatwg-url@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+ integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
+ dependencies:
+ tr46 "~0.0.3"
+ webidl-conversions "^3.0.0"
+
+which@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
+windows-release@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-4.0.0.tgz#4725ec70217d1bf6e02c7772413b29cdde9ec377"
+ integrity sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==
+ dependencies:
+ execa "^4.0.2"
+
+winston-daily-rotate-file@^4.7.1:
+ version "4.7.1"
+ resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-4.7.1.tgz#f60a643af87f8867f23170d8cd87dbe3603a625f"
+ integrity sha512-7LGPiYGBPNyGHLn9z33i96zx/bd71pjBn9tqQzO3I4Tayv94WPmBNwKC7CO1wPHdP9uvu+Md/1nr6VSH9h0iaA==
+ dependencies:
+ file-stream-rotator "^0.6.1"
+ object-hash "^2.0.1"
+ triple-beam "^1.3.0"
+ winston-transport "^4.4.0"
+
+winston-transport@^4.4.0, winston-transport@^4.5.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.6.0.tgz#f1c1a665ad1b366df72199e27892721832a19e1b"
+ integrity sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==
+ dependencies:
+ logform "^2.3.2"
+ readable-stream "^3.6.0"
+ triple-beam "^1.3.0"
+
+winston@^3.11.0:
+ version "3.11.0"
+ resolved "https://registry.yarnpkg.com/winston/-/winston-3.11.0.tgz#2d50b0a695a2758bb1c95279f0a88e858163ed91"
+ integrity sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==
+ dependencies:
+ "@colors/colors" "^1.6.0"
+ "@dabh/diagnostics" "^2.0.2"
+ async "^3.2.3"
+ is-stream "^2.0.0"
+ logform "^2.4.0"
+ one-time "^1.0.0"
+ readable-stream "^3.4.0"
+ safe-stable-stringify "^2.3.1"
+ stack-trace "0.0.x"
+ triple-beam "^1.3.0"
+ winston-transport "^4.5.0"
+
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^6.0.1:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
+ integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
+ integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
+ dependencies:
+ ansi-styles "^6.1.0"
+ string-width "^5.0.1"
+ strip-ansi "^7.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+write-file-atomic@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd"
+ integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==
+ dependencies:
+ imurmurhash "^0.1.4"
+ signal-exit "^3.0.7"
+
+ws@8.14.2:
+ version "8.14.2"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f"
+ integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==
+
+xtend@^4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+ integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yallist@4.0.0, yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yallist@^3.0.2:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
+ integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
+yargs-parser@21.1.1, yargs-parser@^21.0.1, yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs-parser@^20.2.2:
+ version "20.2.9"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
+ integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+
+yargs@^16.0.0:
+ version "16.2.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+ integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+ dependencies:
+ cliui "^7.0.2"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.0"
+ y18n "^5.0.5"
+ yargs-parser "^20.2.2"
+
+yargs@^17.3.1, yargs@^17.6.2:
+ version "17.7.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
+
+yn@3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
+ integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==