diff --git a/.gitignore b/.gitignore index d07a0a67f..dac664ab8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ node_modules yarn-error.log .idea/ +.env diff --git a/README.md b/README.md index 0b226ff91..bdd22fdd8 100644 --- a/README.md +++ b/README.md @@ -8,25 +8,12 @@ The code for [dzcode.io](https://dzcode.io), a website for Algerian open-source You can find more about each folder by clicking on the folder name -| Folder | Coverage | Production URL | Staging URL | -| :------------------- | :----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------: | ---------------------------------------------------: | -| [./web](./web) | [![codecov](https://codecov.io/gh/dzcode-io/dzcode.io/graph/badge.svg?flag=web)](https://codecov.io/gh/dzcode-io/dzcode.io) | [dzcode.io](https://dzcode.io) | [stage.dzcode.io](https://stage.dzcode.io) | -| [./data](./data) | [![codecov](https://codecov.io/gh/dzcode-io/dzcode.io/graph/badge.svg?flag=data)](https://codecov.io/gh/dzcode-io/dzcode.io) | [data.dzcode.io](https://data.dzcode.io) | [data.stage.dzcode.io](https://data.stage.dzcode.io) | -| [./api](./api) | [![codecov](https://codecov.io/gh/dzcode-io/dzcode.io/graph/badge.svg?flag=api)](https://codecov.io/gh/dzcode-io/dzcode.io) | [api.dzcode.io](https://api.dzcode.io) | [api_stage.dzcode.io](https://api_stage.dzcode.io) | -| [./common](./common) | [![codecov](https://codecov.io/gh/dzcode-io/dzcode.io/graph/badge.svg?flag=common)](https://codecov.io/gh/dzcode-io/dzcode.io) | | | - -## Table of Content - -- [dzCode.io](#dzcodeio) - - [Meta](#meta) - - [Table of Content](#table-of-content) - - [Get Started](#get-started) - - [Perquisites](#perquisites) - - [Run it locally](#run-it-locally) - - [Contributing](#contributing) - - [Before You Create a Pull Request](#before-you-create-a-pull-request) - - [List Your Project or Add/Edit Article](#list-your-project-or-addedit-article) - - [License](#license) +| Folder | Coverage | Production URL | Staging URL | Local URL | +| :------------------- | :----------------------------------------------------------------------------------------------------------------------------- | -----------------------------------------------------: | -----------------------------------------------------------------: | ------------------------------------------------------: | +| [./web](./web) | [![codecov](https://codecov.io/gh/dzcode-io/dzcode.io/graph/badge.svg?flag=web)](https://codecov.io/gh/dzcode-io/dzcode.io) | [dzcode.io](https://dzcode.io) | [stage.dzcode.io](https://stage.dzcode.io) | [localhost:8080](http://localhost:8080) | +| [./data](./data) | [![codecov](https://codecov.io/gh/dzcode-io/dzcode.io/graph/badge.svg?flag=data)](https://codecov.io/gh/dzcode-io/dzcode.io) | [data.dzcode.io](https://data.dzcode.io) | [data.stage.dzcode.io](https://data.stage.dzcode.io) | [localhost:9090](http://localhost:9090) | +| [./api](./api) | [![codecov](https://codecov.io/gh/dzcode-io/dzcode.io/graph/badge.svg?flag=api)](https://codecov.io/gh/dzcode-io/dzcode.io) | [api.dzcode.io/v2/docs](https://api.dzcode.io/v2/docs) | [api_stage.dzcode.io/v2/docs](https://api_stage.dzcode.io/v2/docs) | [localhost:7070/v2/docs](http://localhost:7070/v2/docs) | +| [./common](./common) | [![codecov](https://codecov.io/gh/dzcode-io/dzcode.io/graph/badge.svg?flag=common)](https://codecov.io/gh/dzcode-io/dzcode.io) | | | | ## Get Started @@ -64,16 +51,16 @@ yarn yarn dev ``` -- For web server to +- For web server go to - For data server go to -- For api server go to +- For api server go to ## Contributing To get started see [the contributing guidelines](https://github.com/dzcode-io/dzcode.io/blob/master/.github/CONTRIBUTING.md). - ### Before You Create a Pull Request + - If you already forked the repository, please make sure your fork is up-to-date, following [this simple steps](https://www.dzcode.io/Learn/Git_Basics/Syncing_An_Old_Forked_Repository_With_Upstream). - Please make sure your code follows the style guideline defined in this repo, for that simply run `yarn lint:fix` to ensure the conformity. This process should happen automatically whenever you commit your changes, but you can always do it manually when your Pull Request checks are failing due to linting errors. diff --git a/api/.eslintignore b/api/.eslintignore index 8745b4230..3bf297cd4 100644 --- a/api/.eslintignore +++ b/api/.eslintignore @@ -1,7 +1,7 @@ node_modules/ coverage dist -vultr/build +oracle-cloud/build *.* !*.tsx !*.ts diff --git a/api/.gitignore b/api/.gitignore index 7d2b3a678..b7e755384 100644 --- a/api/.gitignore +++ b/api/.gitignore @@ -1,6 +1,6 @@ dist coverage -vultr/build +oracle-cloud/build # logs **.tsbuildinfo diff --git a/api/.prettierignore b/api/.prettierignore index 712dde4fa..ce88e607f 100644 --- a/api/.prettierignore +++ b/api/.prettierignore @@ -1,7 +1,12 @@ node_modules/ coverage dist -vultr/build +oracle-cloud/build .* *.tsbuildinfo +*.log +*.svg +*.jpeg +*.png +*.ico diff --git a/api/README.md b/api/README.md new file mode 100644 index 000000000..f0f58fcb4 --- /dev/null +++ b/api/README.md @@ -0,0 +1,23 @@ +# API code + +## Folder structure + +The app is split into modules, each module (any folder directly under `api/src`) can have service(s) and/or controller(s) + +- example of a service is [./src/github/service.ts](./src/github/service.ts) +- example of a controller is [./contributor/controller.ts](./contributor/controller.ts) + +There is still temporary old code inside: + +- [./src/app/controllers](./src/app/controllers) +- [./src/app/loaders](./src/app/loaders) +- [./src/app/routes](./src/app/routes) +- [./src/app/services](./src/app/services) + +## Dependency injection + +We use typedi for dependency injection, please check their docs. + +We use it in both services and controllers. + +**Note:** if the readme is still unclear, please create a PR with your suggested changes/additions diff --git a/api/jest.config.js b/api/jest.config.js new file mode 100644 index 000000000..2989c25d7 --- /dev/null +++ b/api/jest.config.js @@ -0,0 +1,25 @@ +module.exports = { + testEnvironment: "node", + collectCoverageFrom: ["src/**/*.ts"], + // coverageThreshold: { + // global: { + // branches: 80, + // functions: 80, + // lines: 80, + // statements: 80, + // }, + // }, + transform: { + "^.+\\.(ts)?$": "ts-jest", + }, + coveragePathIgnorePatterns: [ + "node_modules", + "dist", + "src/app/index.ts", + // temporarily until we migrate all endpoints to v2 + "src/app/controllers", + "src/app/routes", + "src/app/services", + "src/app/loaders", + ], +}; diff --git a/api/nodemon.json b/api/nodemon.json new file mode 100644 index 000000000..12b11701e --- /dev/null +++ b/api/nodemon.json @@ -0,0 +1,3 @@ +{ + "watch": ["dist", ".env"] +} diff --git a/api/vultr/Dockerfile b/api/oracle-cloud/Dockerfile similarity index 100% rename from api/vultr/Dockerfile rename to api/oracle-cloud/Dockerfile diff --git a/api/vultr/deploy.js b/api/oracle-cloud/deploy.js similarity index 72% rename from api/vultr/deploy.js rename to api/oracle-cloud/deploy.js index 4c9577675..3ab6f94d6 100644 --- a/api/vultr/deploy.js +++ b/api/oracle-cloud/deploy.js @@ -5,13 +5,19 @@ const cp = require("child_process"); // Coping files console.log("⚙️ Preparing files ..."); -fse.copySync("../package.json", "./vultr/build/package.json"); -fse.copySync("../common/package.json", "./vultr/build/common/package.json"); -fse.copySync("../common/dist", "./vultr/build/common/dist"); -fse.copySync("./package.json", "./vultr/build/api/package.json"); -fse.copySync("./dist", "./vultr/build/api/dist"); -fse.copySync("./vultr/docker-compose.yml", "./vultr/build/docker-compose.yml"); -fse.copySync("./vultr/Dockerfile", "./vultr/build/Dockerfile"); +fse.copySync("../package.json", "./oracle-cloud/build/package.json"); +fse.copySync( + "../common/package.json", + "./oracle-cloud/build/common/package.json", +); +fse.copySync("../common/dist", "./oracle-cloud/build/common/dist"); +fse.copySync("./package.json", "./oracle-cloud/build/api/package.json"); +fse.copySync("./dist", "./oracle-cloud/build/api/dist"); +fse.copySync( + "./oracle-cloud/docker-compose.yml", + "./oracle-cloud/build/docker-compose.yml", +); +fse.copySync("./oracle-cloud/Dockerfile", "./oracle-cloud/build/Dockerfile"); console.log("✅ files copied\n"); // Deploying with ssh @@ -48,7 +54,9 @@ logs = cp.execSync(sshPrefix + '"rm -f -r ' + appPath + '"'); logs = cp.execSync(sshPrefix + '"mkdir ' + appPath + '"'); console.log("⤴️ Uploading new code ..."); -logs = cp.execSync("rsync -r vultr/build/* " + sshServer + ":" + appPath); +logs = cp.execSync( + "rsync -r oracle-cloud/build/* " + sshServer + ":" + appPath, +); console.log("✅ New code uploaded."); console.log("\n⚙️ Starting up the app"); diff --git a/api/vultr/docker-compose.yml b/api/oracle-cloud/docker-compose.yml similarity index 100% rename from api/vultr/docker-compose.yml rename to api/oracle-cloud/docker-compose.yml diff --git a/api/package.json b/api/package.json index 4f199e58f..719151b56 100644 --- a/api/package.json +++ b/api/package.json @@ -1,6 +1,6 @@ { "name": "@dzcode.io/api", - "version": "1.0.0", + "version": "2.0.0", "description": "dzCode.io api code", "scripts": { "lint:check": "yarn prettier:check && yarn eslint:check", @@ -10,15 +10,15 @@ "prettier:check": "prettier \"**/*.*\" --check --ignore-path ./.prettierignore", "prettier:fix": "prettier \"**/*.*\" --write --ignore-path ./.prettierignore", "test": "jest src", - "test:watch": "jest src --watchAll", + "test:watch": "jest --watchAll", "test:cov": "jest src --coverage", - "test:cov:watch": "jest src --coverage --watchAll", + "test:cov:watch": "jest --coverage --watchAll", "build": "tsc", "build:watch": "tsc --watch", - "dev": "nodemon dist/index.js", - "start": "node dist/index.js", - "deploy": "yarn build && rimraf ./vultr/build && node vultr/deploy.js production", - "deploy:stg": "yarn build && rimraf ./vultr/build && node vultr/deploy.js staging" + "dev": "nodemon dist/app/index.js", + "start": "node dist/app/index.js", + "deploy": "yarn build && rimraf ./oracle-cloud/build && node oracle-cloud/deploy.js production", + "deploy:stg": "yarn build && rimraf ./oracle-cloud/build && node oracle-cloud/deploy.js staging" }, "repository": { "type": "git", @@ -39,19 +39,34 @@ "dependencies": { "@dzcode.io/common": "1.0.0", "axios": "^0.21.1", - "body-parser": "^1.19.0", + "class-transformer": "^0.4.0", + "class-validator": "^0.13.1", + "class-validator-jsonschema": "^3.0.1", "cors": "^2.8.5", + "dotenv": "^8.2.0", "express": "^4.17.1", - "morgan": "^1.10.0" + "express-rate-limit": "^5.2.6", + "helmet": "^4.4.1", + "morgan": "^1.10.0", + "reflect-metadata": "^0.1.13", + "routing-controllers": "^0.9.0", + "routing-controllers-openapi": "^3.0.0", + "swagger-ui-express": "^4.1.6", + "typedi": "^0.10.0", + "winston": "^3.3.3" }, "devDependencies": { "@types/body-parser": "^1.19.0", "@types/cors": "^2.8.9", + "@types/dotenv": "^8.2.0", "@types/express": "^4.17.9", + "@types/express-rate-limit": "^5.1.1", "@types/morgan": "^1.9.2", "@types/node": "^14.14.16", + "@types/swagger-ui-express": "^4.1.2", "eslint-config-prettier": "^7.1.0", "fs-extra": "^9.0.1", + "jest-mock-extended": "^1.0.13", "lint-staged": "^10.5.3", "nodemon": "^2.0.6", "typescript": "^4.1.3" diff --git a/api/src/controllers/contributors/index.ts b/api/src/app/controllers/contributors/index.ts similarity index 100% rename from api/src/controllers/contributors/index.ts rename to api/src/app/controllers/contributors/index.ts diff --git a/api/src/controllers/etc/index.ts b/api/src/app/controllers/etc/index.ts similarity index 100% rename from api/src/controllers/etc/index.ts rename to api/src/app/controllers/etc/index.ts diff --git a/api/src/controllers/github/index.ts b/api/src/app/controllers/github/index.ts similarity index 100% rename from api/src/controllers/github/index.ts rename to api/src/app/controllers/github/index.ts diff --git a/api/src/app/index.ts b/api/src/app/index.ts new file mode 100644 index 000000000..0d182be81 --- /dev/null +++ b/api/src/app/index.ts @@ -0,0 +1,45 @@ +import "reflect-metadata"; + +import { createExpressServer, useContainer } from "routing-controllers"; +import { Application } from "express"; +import { ConfigService } from "../config/service"; +import Container from "typedi"; +import { ContributorController } from "../contributor/controller"; +import { DocsMiddleware } from "./middlewares/docs"; +import { ErrorMiddleware } from "./middlewares/error"; +import { LoggerMiddleware } from "./middlewares/logger"; +import { LoggerService } from "../logger/service"; +import { SecurityMiddleware } from "./middlewares/security"; +import { fsConfig } from "@dzcode.io/common/dist/config"; +import router from "./routes/api"; + +// Use typedi container +useContainer(Container); + +// Create the app: +export const routingControllersOptions = { + controllers: [ContributorController], + middlewares: [ + // middlewares: + SecurityMiddleware, + ErrorMiddleware, + LoggerMiddleware, + DocsMiddleware, + ], + routePrefix: "/v2", + defaultErrorHandler: false, + cors: Container.get(SecurityMiddleware).cors(), +}; +const app: Application = createExpressServer(routingControllersOptions); + +// Load old code to the app, temporarily until we migrate all endpoints +app.use("/", router); + +const { ENV, PORT } = Container.get(ConfigService).env(); +const logger = Container.get(LoggerService); + +// Start it +app.listen(PORT, () => { + const commonConfig = fsConfig(ENV); + logger.info({ message: `API Server up on: ${commonConfig.api.url}/v2/docs` }); +}); diff --git a/api/src/app/loaders/index.ts b/api/src/app/loaders/index.ts new file mode 100644 index 000000000..b100a09ac --- /dev/null +++ b/api/src/app/loaders/index.ts @@ -0,0 +1,8 @@ +import { Router } from "express"; +import { parserLoader } from "./parser"; + +export const rootLoader: Loader = (params) => { + parserLoader(params); +}; + +export type Loader = (params: { app: Router }) => void; diff --git a/api/src/app/loaders/parser.ts b/api/src/app/loaders/parser.ts new file mode 100644 index 000000000..225823f88 --- /dev/null +++ b/api/src/app/loaders/parser.ts @@ -0,0 +1,8 @@ +import { json, urlencoded } from "express"; + +import { Loader } from "."; + +export const parserLoader: Loader = ({ app }) => { + app.use(json()); + app.use(urlencoded()); +}; diff --git a/api/src/app/middlewares/docs.ts b/api/src/app/middlewares/docs.ts new file mode 100644 index 000000000..b5a696940 --- /dev/null +++ b/api/src/app/middlewares/docs.ts @@ -0,0 +1,39 @@ +import { ExpressMiddlewareInterface, Middleware } from "routing-controllers"; +import { RequestHandler, Router } from "express"; +import { serve, setup } from "swagger-ui-express"; + +import { Service } from "typedi"; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { defaultMetadataStorage } = require("class-transformer/cjs/storage"); +import { getMetadataArgsStorage } from "routing-controllers"; +import { routingControllersOptions } from ".."; +import { routingControllersToSpec } from "routing-controllers-openapi"; +import { validationMetadatasToSchemas } from "class-validator-jsonschema"; + +@Service() +@Middleware({ type: "after" }) +export class DocsMiddleware implements ExpressMiddlewareInterface { + constructor() { + // Parse class-validator classes into JSON Schema: + const schemas = validationMetadatasToSchemas({ + refPointerPrefix: "#/components/schemas/", + classTransformerMetadataStorage: defaultMetadataStorage, + }); + // Parse routing-controllers classes into OpenAPI spec: + const storage = getMetadataArgsStorage(); + const spec = routingControllersToSpec(storage, routingControllersOptions, { + components: { schemas }, + info: { + description: "swagger documentation for version 2 of dzcode.io API", + title: "dzcode.io API v2", + version: "2.0.0", + }, + }); + + this.router.use("/v2/docs", serve, setup(spec)); + } + + private router = Router(); + + use: RequestHandler = this.router; +} diff --git a/api/src/app/middlewares/error.ts b/api/src/app/middlewares/error.ts new file mode 100644 index 000000000..af257d904 --- /dev/null +++ b/api/src/app/middlewares/error.ts @@ -0,0 +1,38 @@ +import { + ExpressErrorMiddlewareInterface, + Middleware, +} from "routing-controllers"; +import { ErrorRequestHandler } from "express"; +import { GeneralResponseDto } from "../types"; +import { LoggerService } from "../../logger/service"; +import { Service } from "typedi"; + +@Service() +@Middleware({ type: "after" }) +export class ErrorMiddleware implements ExpressErrorMiddlewareInterface { + constructor(private loggerService: LoggerService) {} + + error: ErrorRequestHandler = ( + err, + req, + res, + next, + ) => { + // Logs error + this.loggerService.error({ + message: "Internal Server Error", + error: err?.message, + }); + + // Skip if headers are already sent + if (res.headersSent) { + return next(err); + } + + // return a general error response + return res.status(500).json({ + code: 500, + msg: err?.message, + }); + }; +} diff --git a/api/src/app/middlewares/logger.ts b/api/src/app/middlewares/logger.ts new file mode 100644 index 000000000..4042d33b3 --- /dev/null +++ b/api/src/app/middlewares/logger.ts @@ -0,0 +1,23 @@ +import { ExpressMiddlewareInterface, Middleware } from "routing-controllers"; +import { LogLevel, LoggerService } from "../../logger/service"; +import { RequestHandler } from "express"; +import { Service } from "typedi"; + +@Service() +@Middleware({ type: "after" }) +export class LoggerMiddleware implements ExpressMiddlewareInterface { + constructor(private loggerService: LoggerService) {} + + use: RequestHandler = (req, res, next) => { + let logLevel: LogLevel = "info"; + const { statusCode } = res; + if (statusCode < 100 && statusCode >= 400) { + logLevel = "error"; + } + + this.loggerService.log(logLevel, { + message: `${res.statusCode} ${req.method} ${req.url}`, + }); + next(); + }; +} diff --git a/api/src/app/middlewares/security.ts b/api/src/app/middlewares/security.ts new file mode 100644 index 000000000..dcb257b96 --- /dev/null +++ b/api/src/app/middlewares/security.ts @@ -0,0 +1,40 @@ +import { ExpressMiddlewareInterface, Middleware } from "routing-controllers"; +import { RequestHandler, Router } from "express"; + +import { ConfigService } from "../../config/service"; +import { Service } from "typedi"; +import helmet from "helmet"; +import rateLimit from "express-rate-limit"; + +@Service() +@Middleware({ type: "before" }) +export class SecurityMiddleware implements ExpressMiddlewareInterface { + constructor(private configService: ConfigService) { + this.router.use(helmet()); + + this.router.use( + rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, // limit each IP to 100 requests per windowMs + }), + ); + } + + private router = Router(); + + use: RequestHandler = this.router; + + public cors = () => { + const env = this.configService.env().ENV; + return { + origin: + env === "development" + ? ["http://localhost:8080"] + : env === "staging" + ? ["https://stage.dzcode.io"] + : env === "production" + ? ["https://www.dzcode.io"] + : true, + }; + }; +} diff --git a/api/src/routes/api/contributors/index.ts b/api/src/app/routes/api/contributors/index.ts similarity index 100% rename from api/src/routes/api/contributors/index.ts rename to api/src/app/routes/api/contributors/index.ts diff --git a/api/src/routes/api/github/index.ts b/api/src/app/routes/api/github/index.ts similarity index 100% rename from api/src/routes/api/github/index.ts rename to api/src/app/routes/api/github/index.ts diff --git a/api/src/routes/api/index.ts b/api/src/app/routes/api/index.ts similarity index 100% rename from api/src/routes/api/index.ts rename to api/src/app/routes/api/index.ts diff --git a/api/src/routes/index.ts b/api/src/app/routes/index.ts similarity index 83% rename from api/src/routes/index.ts rename to api/src/app/routes/index.ts index a1d16b04d..4dc8b9425 100644 --- a/api/src/routes/index.ts +++ b/api/src/app/routes/index.ts @@ -1,9 +1,12 @@ import { Request, Response, Router } from "express"; import api from "./api"; +import { rootLoader } from "../loaders"; const router: Router = Router(); +rootLoader({ app: router }); + // API routes router.use("/", api); diff --git a/api/src/services/github/index.ts b/api/src/app/services/github/index.ts similarity index 98% rename from api/src/services/github/index.ts rename to api/src/app/services/github/index.ts index 8ff322d84..2546024b3 100644 --- a/api/src/services/github/index.ts +++ b/api/src/app/services/github/index.ts @@ -1,4 +1,4 @@ -import { ListContributorsResponse } from "./types"; +import { ListContributorsResponse } from "../../../github/types"; import axios from "axios"; export const listOrganizationRepositories = async ({ diff --git a/api/src/app/types/index.ts b/api/src/app/types/index.ts new file mode 100644 index 000000000..2ad143283 --- /dev/null +++ b/api/src/app/types/index.ts @@ -0,0 +1,15 @@ +import { IsNumber, IsObject, IsOptional, IsString } from "class-validator"; + +export class GeneralResponseDto { + @IsNumber() + @IsOptional() + code?: number; + + @IsString() + @IsOptional() + msg?: string; + + @IsObject() + @IsOptional() + debug?: Record; +} diff --git a/api/src/config/dto.ts b/api/src/config/dto.ts new file mode 100644 index 000000000..8101419bf --- /dev/null +++ b/api/src/config/dto.ts @@ -0,0 +1,11 @@ +import { Environment } from "@dzcode.io/common/dist/types"; +import { Matches } from "class-validator"; + +const environment: Environment[] = ["development", "staging", "production"]; + +export class ENVDto { + PORT = 7070; + + @Matches("(" + environment.join(")|(") + ")") + ENV: Environment = "development"; +} diff --git a/api/src/config/index.spec.ts b/api/src/config/index.spec.ts deleted file mode 100644 index c7abc7ad5..000000000 --- a/api/src/config/index.spec.ts +++ /dev/null @@ -1,5 +0,0 @@ -describe("Mock test", () => { - test("expect 1+1 to be 2", () => { - expect(1 + 1).toBe(2); - }); -}); diff --git a/api/src/config/index.ts b/api/src/config/index.ts deleted file mode 100644 index cd6b66c99..000000000 --- a/api/src/config/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Environment } from "@dzcode.io/common/dist/types"; -import { fsConfig } from "@dzcode.io/common/dist/config"; -export const fullstackConfig = fsConfig( - (process.env as unknown) as Environment, -); diff --git a/api/src/config/service.spec.ts b/api/src/config/service.spec.ts new file mode 100644 index 000000000..7eca7c79d --- /dev/null +++ b/api/src/config/service.spec.ts @@ -0,0 +1,23 @@ +import { ConfigService } from "./service"; +import dotenv from "dotenv"; + +jest.mock("dotenv"); +const mockedDotenv = dotenv as jest.Mocked; + +describe("ConfigService", () => { + it("should throw error when .env has invalid key value pair", async () => { + mockedDotenv.config.mockReturnValue({ parsed: { ENV: "testing" } }); + + expect(() => new ConfigService()).toThrowError( + `⚠️ Errors in .env file in the following keys:\nENV : {\"matches\":\"ENV must match (development)|(staging)|(production) regular expression\"}`, + ); + }); + + it("should return default envs when .env is empty or doesn't exists", async () => { + mockedDotenv.config.mockReturnValue({ error: new Error("test-error") }); + + const configService = new ConfigService(); + expect(configService).toBeInstanceOf(ConfigService); + expect(configService.env()).toMatchObject({ ENV: "development" }); + }); +}); diff --git a/api/src/config/service.ts b/api/src/config/service.ts new file mode 100644 index 000000000..bd3f340fd --- /dev/null +++ b/api/src/config/service.ts @@ -0,0 +1,37 @@ +import { ENVDto } from "./dto"; +import { Service } from "typedi"; +import { config } from "dotenv"; +import { plainToClass } from "class-transformer"; +import { validateSync } from "class-validator"; + +let _env: ENVDto; + +@Service() +export class ConfigService { + constructor() { + this.generateConfig(); + } + + public env = () => _env; + + private generateConfig = () => { + const _config = config(); + const output = plainToClass(ENVDto, { + ...process.env, + ...(_config.parsed || {}), + }); + + const errors = validateSync(output); + + if (errors.length > 0) + throw new Error( + `⚠️ Errors in .env file in the following keys:${errors.reduce( + (pV, cV) => + (pV += "\n" + cV.property + " : " + JSON.stringify(cV.constraints)), + "", + )}`, + ); + + _env = output; + }; +} diff --git a/api/src/contributor/controller.spec.ts b/api/src/contributor/controller.spec.ts new file mode 100644 index 000000000..81db3b8de --- /dev/null +++ b/api/src/contributor/controller.spec.ts @@ -0,0 +1,52 @@ +import { + githubUserMock, + githubUserMock2, + githubUserMock3, +} from "../../test/mocks"; + +import { ContributorController } from "./controller"; +import { GetContributorsResponseDto } from "./types"; +import { GithubService } from "../github/service"; +import { mock } from "jest-mock-extended"; + +describe("ContributorController", () => { + const mockedGithubServiceInstance = mock(); + const contributorsMock = [githubUserMock2, githubUserMock, githubUserMock3]; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("should throw error when GithubService fails", async () => { + mockedGithubServiceInstance.listContributors.mockRejectedValue({ + meg: "service down", + }); + + const contributorController = new ContributorController( + mockedGithubServiceInstance, + ); + let errorThrown = false; + try { + await contributorController.getContributor("/"); + } catch (error) { + errorThrown = error; + } + expect(errorThrown).toMatchObject({ meg: "service down" }); + }); + + it("should return list of contributors when GithubService succeed", async () => { + mockedGithubServiceInstance.listContributors.mockResolvedValue( + contributorsMock, + ); + + const contributorController = new ContributorController( + mockedGithubServiceInstance, + ); + + const contributors = await contributorController.getContributor("/"); + + expect(contributors).toMatchObject({ + contributors: contributorsMock, + }); + }); +}); diff --git a/api/src/contributor/controller.ts b/api/src/contributor/controller.ts new file mode 100644 index 000000000..b436f960e --- /dev/null +++ b/api/src/contributor/controller.ts @@ -0,0 +1,55 @@ +import { Controller, Get, QueryParam } from "routing-controllers"; +import { OpenAPI, ResponseSchema } from "routing-controllers-openapi"; +import { GetContributorsResponseDto } from "./types"; +import { GithubService } from "../github/service"; +import { GithubUserDto } from "../github/dto"; +import { Service } from "typedi"; + +@Service() +@Controller("/Contributors") +export class ContributorController { + constructor(private readonly githubService: GithubService) {} + + @Get("/") + @OpenAPI({ + summary: + "Return a list of github users that contributed to data/[path] directory", + }) + @ResponseSchema(GetContributorsResponseDto) + public async getContributor( + @QueryParam("path") path: string, + ): Promise { + const responses = await Promise.all([ + // current place for data: + this.githubService.listContributors({ + owner: "dzcode-io", + repo: "dzcode.io", + path: `data/models/${path}`, + }), + // also check old place for data, to not lose contribution effort: + this.githubService.listContributors({ + owner: "dzcode-io", + repo: "dzcode.io", + path: `data/${path}`, + }), + ]); + + // filter and sort contributors: + const uniqUsernames: Record = {}; + const contributors = [...responses[0], ...responses[1]] + .reduce((pV, cV) => { + if (uniqUsernames[cV.login]) { + uniqUsernames[cV.login]++; + return pV; + } else { + uniqUsernames[cV.login] = 1; + return [...pV, cV]; + } + }, []) + .sort((a, b) => uniqUsernames[b.login] - uniqUsernames[a.login]); + + return { + contributors, + }; + } +} diff --git a/api/src/contributor/types.ts b/api/src/contributor/types.ts new file mode 100644 index 000000000..0dc1e67cd --- /dev/null +++ b/api/src/contributor/types.ts @@ -0,0 +1,11 @@ +import {} from "module"; +import { GeneralResponseDto } from "../app/types"; +import { GithubUserDto } from "../github/dto"; +import { Type } from "class-transformer"; +import { ValidateNested } from "class-validator"; + +export class GetContributorsResponseDto extends GeneralResponseDto { + @ValidateNested({ each: true }) + @Type(() => GithubUserDto) + contributors?: GithubUserDto[]; +} diff --git a/api/src/github/dto.ts b/api/src/github/dto.ts new file mode 100644 index 000000000..a6aee61ce --- /dev/null +++ b/api/src/github/dto.ts @@ -0,0 +1,15 @@ +import { GithubUser } from "@dzcode.io/common/dist/types"; +import { IsString } from "class-validator"; + +export class GithubUserDto implements GithubUser { + @IsString() + avatar_url!: string; // eslint-disable-line camelcase + @IsString() + html_url!: string; // eslint-disable-line camelcase + @IsString() + id!: string; + @IsString() + login!: string; + @IsString() + type!: string; +} diff --git a/api/src/github/service.spec.ts b/api/src/github/service.spec.ts new file mode 100644 index 000000000..979146435 --- /dev/null +++ b/api/src/github/service.spec.ts @@ -0,0 +1,42 @@ +import { GeneralGithubQuery, ListContributorsResponse } from "./types"; + +import Axios from "axios"; +import { GithubService } from "./service"; +import { githubUserMock } from "../../test/mocks"; + +jest.mock("axios"); +const mockedAxios = Axios as jest.Mocked; + +describe("GithubService", () => { + const githubQuery: GeneralGithubQuery = { + owner: "test-owner", + repo: "test-repo", + path: "test/path", + }; + const contributorsMock: ListContributorsResponse = [ + { + author: githubUserMock, + committer: githubUserMock, + }, + ]; + + it("should throw error when api call fails", async () => { + mockedAxios.get.mockRejectedValue({ meg: "service down" }); + const githubService = new GithubService(); + let errorThrown = false; + try { + await githubService.listContributors(githubQuery); + } catch (error) { + errorThrown = error; + } + expect(errorThrown).toMatchObject({ meg: "service down" }); + }); + + it("should return list of contributors when api call succeed", async () => { + mockedAxios.get.mockResolvedValue({ data: contributorsMock }); + const githubService = new GithubService(); + const contributors = await githubService.listContributors(githubQuery); + + expect(contributors).toMatchObject([githubUserMock]); + }); +}); diff --git a/api/src/github/service.ts b/api/src/github/service.ts new file mode 100644 index 000000000..63d493776 --- /dev/null +++ b/api/src/github/service.ts @@ -0,0 +1,32 @@ +import { GeneralGithubQuery, ListContributorsResponse } from "./types"; + +import { Service } from "typedi"; +import axios from "axios"; + +@Service() +export class GithubService { + public listContributors = async ({ + owner, + repo, + path, + }: GeneralGithubQuery) => { + const response = await axios.get( + `${this.apiURL}/repos/${owner}/${repo}/commits?path=${path}`, + // eslint-disable-next-line camelcase + { params: { state: "all", per_page: 10 } }, + ); + const contributors = response.data.map( + // eslint-disable-next-line camelcase + ({ committer: { login, avatar_url, html_url, type, id } }) => ({ + id, + login, + avatar_url, // eslint-disable-line camelcase + html_url, // eslint-disable-line camelcase + type, + }), + ); + return contributors; + }; + + private apiURL = "https://api.github.com"; +} diff --git a/api/src/services/github/types.ts b/api/src/github/types.ts similarity index 63% rename from api/src/services/github/types.ts rename to api/src/github/types.ts index 249dfc573..864d5deb0 100644 --- a/api/src/services/github/types.ts +++ b/api/src/github/types.ts @@ -4,3 +4,9 @@ export type ListContributorsResponse = Array<{ author: GithubUser; committer: GithubUser; }>; + +export interface GeneralGithubQuery { + owner: string; + repo: string; + path: string; +} diff --git a/api/src/index.ts b/api/src/index.ts deleted file mode 100644 index 5cd96cfe4..000000000 --- a/api/src/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import express from "express"; -import { fullstackConfig } from "./config"; -import loader from "./loaders"; -import routes from "./routes"; - -const app = express(); -const port = process.env.PORT || fullstackConfig.api.port; - -loader.init({ app }); - -app.use(routes); - -// Start the server -app.listen(port, () => - console.log(`Api server listening at http://localhost:${port}`), -); diff --git a/api/src/loaders/express-loader.ts b/api/src/loaders/express-loader.ts deleted file mode 100644 index 51c16f22c..000000000 --- a/api/src/loaders/express-loader.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Application } from "express"; -import bodyParser from "body-parser"; -import cors from "cors"; -import morgan from "morgan"; - -export default function expressLoader({ app }: { app: Application }): void { - app.use( - cors({ - allowedHeaders: - process.env.NODE_ENV === "development" - ? ["http://localhost:8080"] - : ["https://www.dzcode.io", "https://stage.dzcode.io"], - origin: true, - }), - ); - app.use(morgan("dev")); - app.use(bodyParser.json()); -} diff --git a/api/src/loaders/index.ts b/api/src/loaders/index.ts deleted file mode 100644 index a42ec66e3..000000000 --- a/api/src/loaders/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Application } from "express"; -import expressLoader from "./express-loader"; - -export default { - init({ app }: { app: Application }): void { - expressLoader({ app }); - }, -}; diff --git a/api/src/logger/service.ts b/api/src/logger/service.ts new file mode 100644 index 000000000..cb21545c1 --- /dev/null +++ b/api/src/logger/service.ts @@ -0,0 +1,60 @@ +import { Service } from "typedi"; +import winston from "winston"; + +@Service() +export class LoggerService { + constructor() { + this.logger = winston.createLogger({ + level: "info", + format: winston.format.json(), + transports: [ + new winston.transports.Console({ + format: winston.format.combine( + winston.format.colorize(), + winston.format.simple(), + ), + }), + ], + }); + } + + public log(level: LogLevel, logInfo: LogObject) { + this.logger.log(level, logInfo.message, { ...logInfo, message: undefined }); + } + + public info(logInfo: LogObject) { + this.logger.log("info", logInfo.message, { + ...logInfo, + message: undefined, + }); + } + + public error(logInfo: LogObject) { + this.logger.log("error", logInfo.message, { + ...logInfo, + message: undefined, + }); + } + + public debug(logInfo: LogObject) { + this.logger.log("debug", logInfo.message, { + ...logInfo, + message: undefined, + }); + } + + public warn(logInfo: LogObject) { + this.logger.log("warn", logInfo.message, { + ...logInfo, + message: undefined, + }); + } + + private logger; +} + +export type LogLevel = "info" | "error" | "debug" | "warn"; +type LogObject = { + message: string; + [key: string]: unknown; +}; diff --git a/api/test/mocks.ts b/api/test/mocks.ts new file mode 100644 index 000000000..e313dbf59 --- /dev/null +++ b/api/test/mocks.ts @@ -0,0 +1,25 @@ +import { GithubUser } from "@dzcode.io/common/dist/types"; + +export const githubUserMock: GithubUser = { + avatar_url: "avatar_url", // eslint-disable-line camelcase + html_url: "html_url", // eslint-disable-line camelcase + id: "id", + login: "login", + type: "type", +}; + +export const githubUserMock2: GithubUser = { + avatar_url: "avatar_url2", // eslint-disable-line camelcase + html_url: "html_url2", // eslint-disable-line camelcase + id: "id2", + login: "login2", + type: "type2", +}; + +export const githubUserMock3: GithubUser = { + avatar_url: "avatar_url3", // eslint-disable-line camelcase + html_url: "html_url3", // eslint-disable-line camelcase + id: "id3", + login: "login3", + type: "type3", +}; diff --git a/api/tsconfig.json b/api/tsconfig.json index d05370bd5..9ef959b4d 100644 --- a/api/tsconfig.json +++ b/api/tsconfig.json @@ -14,8 +14,8 @@ "target": "es2017", "sourceMap": true, "declaration": true, - "outDir": "dist", - "rootDir": "src" + "outDir": "dist" }, - "include": ["src"] + "include": ["src/**/*"], + "exclude": ["**/*.spec.ts"] } diff --git a/package.json b/package.json index 9c60808c4..33d9ba509 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "lint:check": "concurrently \"cd api && yarn lint:check\" \"cd common && yarn lint:check\" \"cd data && yarn lint:check\" \"cd web && yarn lint:check\"", "lint:fix": "concurrently \"cd api && yarn lint:fix\" \"cd common && yarn lint:fix\" \"cd data && yarn lint:fix\" \"cd web && yarn lint:fix\"", "test": "concurrently \"cd api && yarn test\" \"cd common && yarn test\" \"cd data && yarn test\" \"cd web && yarn test\"", - "test:cov": "concurrently \"cd api && yarn test:cov\" \"cd common && yarn test:cov\" \"cd data && yarn test:cov\" \"cd web && yarn test:cov\"" + "test:cov": "concurrently \"cd api && yarn test:cov\" \"cd common && yarn test:cov\" \"cd data && yarn test:cov\" \"cd web && yarn test:cov\"", + "prepare": "husky-run install" }, "husky": { "hooks": { diff --git a/yarn.lock b/yarn.lock index 5a5293ebf..c03b6e411 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1704,6 +1704,13 @@ resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.9.tgz#4bd1fcac72eca8d5bec93e76c7fdcbdc1bc2cd4a" integrity sha512-zurD1ibz21BRlAOIKP8yhrxlqKx6L9VCwkB5kMiP6nZAhoF5MvC7qS1qPA7nRcr1GJolfkQC7/EAL4hdYejLtg== +"@types/dotenv@^8.2.0": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@types/dotenv/-/dotenv-8.2.0.tgz#5cd64710c3c98e82d9d15844375a33bf1b45d053" + integrity sha512-ylSC9GhfRH7m1EUXBXofhgx4lUWmFeQDINW5oLuS+gxWdfUeW4zJdeVTYVkexEW+e2VUvlZR2kGnGGipAWR7kw== + dependencies: + dotenv "*" + "@types/duplexify@^3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@types/duplexify/-/duplexify-3.6.0.tgz#dfc82b64bd3a2168f5bd26444af165bf0237dcd8" @@ -1737,6 +1744,13 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.45.tgz#e9387572998e5ecdac221950dab3e8c3b16af884" integrity sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g== +"@types/express-rate-limit@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/express-rate-limit/-/express-rate-limit-5.1.1.tgz#e5b0239d18c1580e52ae56dce4248333302a1dc8" + integrity sha512-6oMYZBLlhxC5sdcRXXz528QyfGz3zTy9YdHwqlxLfgx5Cd3zwYaUjjPpJcaTtHmRefLi9P8kLBPz2wB7yz4JtQ== + dependencies: + "@types/express" "*" + "@types/express-serve-static-core@^4.17.18": version "4.17.18" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.18.tgz#8371e260f40e0e1ca0c116a9afcd9426fa094c40" @@ -1746,7 +1760,7 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/express@^4.17.9": +"@types/express@*", "@types/express@^4.17.9": version "4.17.11" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545" integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg== @@ -2016,6 +2030,14 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw== +"@types/swagger-ui-express@^4.1.2": + version "4.1.2" + resolved "https://registry.yarnpkg.com/@types/swagger-ui-express/-/swagger-ui-express-4.1.2.tgz#cfc884904a104c3193f46f423d04ee0416be1ef4" + integrity sha512-t9teFTU8dKe69rX9EwL6OM2hbVquYdFM+sQ0REny4RalPlxAm+zyP04B12j4c7qEuDS6CnlwICywqWStPA3v4g== + dependencies: + "@types/express" "*" + "@types/serve-static" "*" + "@types/tapable@*", "@types/tapable@^1.0.5": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.6.tgz#a9ca4b70a18b270ccb2bc0aaafefd1d486b7ea74" @@ -2033,6 +2055,11 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== +"@types/validator@^13.1.3": + version "13.1.3" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.1.3.tgz#366b394aa3fbeed2392bf0a20ded606fa4a3d35e" + integrity sha512-DaOWN1zf7j+8nHhqXhIgNmS+ltAC53NXqGxYuBhWqWgqolRhddKzfZU814lkHQSTG0IUfQxU7Cg0gb8fFWo2mA== + "@types/webpack-sources@*": version "2.1.0" resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-2.1.0.tgz#8882b0bd62d1e0ce62f183d0d01b72e6e82e8c10" @@ -2310,7 +2337,7 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" -accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: +accepts@^1.3.5, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== @@ -2474,6 +2501,11 @@ ansicolors@~0.3.2: resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= +any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + anymatch@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" @@ -2498,6 +2530,16 @@ anymatch@^3.0.3, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +append-field@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/append-field/-/append-field-0.1.0.tgz#6ddc58fa083c7bc545d3c5995b2830cc2366d44a" + integrity sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo= + +append-field@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" + integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= + aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -3171,6 +3213,14 @@ buffers@~0.1.1: resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= +busboy@^0.2.11: + version "0.2.14" + resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" + integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM= + dependencies: + dicer "0.2.5" + readable-stream "1.1.x" + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -3196,6 +3246,14 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +cache-content-type@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c" + integrity sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA== + dependencies: + mime-types "^2.1.18" + ylru "^1.2.0" + cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -3458,6 +3516,11 @@ cjson@^0.3.1: dependencies: json-parse-helpfulerror "^1.0.3" +class-transformer@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.4.0.tgz#b52144117b423c516afb44cc1c76dbad31c2165b" + integrity sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA== + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -3468,6 +3531,26 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +class-validator-jsonschema@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/class-validator-jsonschema/-/class-validator-jsonschema-3.0.1.tgz#22e7ca733330663a1a2c68bc5f64355253524dd6" + integrity sha512-ynQ7adDhT+1VFNR7q5Q8bEZwZQxi0//81t2mlg+tf+lN711iw/XQvYY7xgyb5n9bh9mRP+VzyH00BNY9jVyVRQ== + dependencies: + lodash.groupby "^4.6.0" + lodash.merge "^4.6.2" + openapi3-ts "^2.0.0" + reflect-metadata "^0.1.13" + tslib "^2.0.3" + +class-validator@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.13.1.tgz#381b2001ee6b9e05afd133671fbdf760da7dec67" + integrity sha512-zWIeYFhUitvAHBwNhDdCRK09hWx+P0HUwFE8US8/CxFpMVzkUK8RJl7yOIE+BVu2lxyPNgeOaFv78tLE47jBIg== + dependencies: + "@types/validator" "^13.1.3" + libphonenumber-js "^1.9.7" + validator "^13.5.2" + clean-css@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" @@ -3597,6 +3680,16 @@ clsx@^1.0.4: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== +co-body@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/co-body/-/co-body-6.1.0.tgz#d87a8efc3564f9bfe3aced8ef5cd04c7a8766547" + integrity sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ== + dependencies: + inflation "^2.0.0" + qs "^6.5.2" + raw-body "^2.3.3" + type-is "^1.6.16" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -3779,6 +3872,16 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +concat-stream@^1.5.0, 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" + concurrently@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-5.3.0.tgz#7500de6410d043c912b2da27de3202cb489b1e7b" @@ -3834,7 +3937,7 @@ constantinople@^4.0.1: "@babel/parser" "^7.6.0" "@babel/types" "^7.6.1" -content-disposition@0.5.3: +content-disposition@0.5.3, content-disposition@~0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== @@ -3863,6 +3966,19 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== +cookie@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + +cookies@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90" + integrity sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow== + dependencies: + depd "~2.0.0" + keygrip "~1.1.0" + copy-anything@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.1.tgz#2afbce6da684bdfcbec93752fa762819cb480d9a" @@ -3875,6 +3991,11 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +copy-to@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/copy-to/-/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5" + integrity sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU= + core-js-compat@^3.8.0: version "3.8.3" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.8.3.tgz#9123fb6b9cad30f0651332dc77deba48ef9b0b3f" @@ -4268,13 +4389,20 @@ debug@4, debug@4.3.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0: dependencies: ms "2.1.2" -debug@^3.1.1, debug@^3.2.6: +debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" +debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -4314,6 +4442,11 @@ deep-equal@^1.0.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -4420,16 +4553,16 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +depd@^2.0.0, 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== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -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.0.4, destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -4445,6 +4578,14 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== +dicer@0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" + integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8= + dependencies: + readable-stream "1.1.x" + streamsearch "0.1.2" + diff-sequences@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" @@ -4566,6 +4707,11 @@ dot-prop@^5.2.0: dependencies: is-obj "^2.0.0" +dotenv@*, dotenv@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + dotenv@^6.1.0: version "6.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" @@ -4648,7 +4794,7 @@ enabled@2.0.x: resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== -encodeurl@~1.0.2: +encodeurl@^1.0.2, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= @@ -4806,7 +4952,7 @@ escape-goat@^2.0.0: resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== -escape-html@~1.0.3: +escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= @@ -5174,6 +5320,25 @@ expect@^26.6.2: jest-message-util "^26.6.2" jest-regex-util "^26.0.0" +express-rate-limit@^5.2.6: + version "5.2.6" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-5.2.6.tgz#b454e1be8a252081bda58460e0a25bf43ee0f7b0" + integrity sha512-nE96xaxGfxiS5jP3tD3kIW1Jg9yQgX0rXCs3rCkZtmbWHEGyotwaezkLj7bnB41Z0uaOLM8W4AX6qHao4IZ2YA== + +express-session@^1.17.1: + version "1.17.1" + resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.1.tgz#36ecbc7034566d38c8509885c044d461c11bf357" + integrity sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q== + dependencies: + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~2.0.0" + on-headers "~1.0.2" + parseurl "~1.3.3" + safe-buffer "5.2.0" + uid-safe "~2.1.5" + express@^4.16.4, express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" @@ -5657,7 +5822,7 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fresh@0.5.2: +fresh@0.5.2, fresh@~0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= @@ -6178,6 +6343,11 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +helmet@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-4.4.1.tgz#a17e1444d81d7a83ddc6e6f9bc6e2055b994efe7" + integrity sha512-G8tp0wUMI7i8wkMk2xLcEvESg5PiCitFMYgGRc/PwULB0RVhTP5GFdxOwvJwp9XVha8CuS8mnhmE8I/8dx/pbw== + hex-color-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" @@ -6299,6 +6469,14 @@ htmlparser2@^3.10.1: inherits "^2.0.1" readable-stream "^3.1.1" +http-assert@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.4.1.tgz#c5f725d677aa7e873ef736199b89686cceb37878" + integrity sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw== + dependencies: + deep-equal "~1.0.1" + http-errors "~1.7.2" + http-cache-semantics@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" @@ -6331,6 +6509,17 @@ http-errors@1.7.3, http-errors@~1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" +http-errors@^1.3.1, http-errors@^1.6.3: + version "1.8.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507" + integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + http-errors@~1.6.2: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" @@ -6535,6 +6724,11 @@ indexes-of@^1.0.1: resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= +inflation@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f" + integrity sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8= + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -6849,6 +7043,11 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-generator-function@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.8.tgz#dfb5c2b120e02b0a8d9d2c6806cd5621aa922f7b" + integrity sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ== + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -7341,6 +7540,13 @@ jest-message-util@^26.6.2: slash "^3.0.0" stack-utils "^2.0.2" +jest-mock-extended@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/jest-mock-extended/-/jest-mock-extended-1.0.13.tgz#07d7b58ea45a4bad8d95ff8ae30ca8f6171c9289" + integrity sha512-fs621RgUK9Z6frJWDA75Gb9Vpm1d9HbpuAWjIu12hZTNls+VVdlJl/43xrqz70CYUbJPnfkiTfLwue9mkKC1ww== + dependencies: + ts-essentials "^4.0.0" + jest-mock@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" @@ -7870,6 +8076,13 @@ jws@^4.0.0: jwa "^2.0.0" safe-buffer "^5.0.1" +keygrip@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226" + integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ== + dependencies: + tsscmp "1.0.6" + keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -7916,6 +8129,82 @@ klona@^2.0.4: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== +koa-bodyparser@^4.2.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-4.3.0.tgz#274c778555ff48fa221ee7f36a9fbdbace22759a" + integrity sha512-uyV8G29KAGwZc4q/0WUAjH+Tsmuv9ImfBUF2oZVyZtaeo0husInagyn/JH85xMSxM0hEk/mbCII5ubLDuqW/Rw== + dependencies: + co-body "^6.0.0" + copy-to "^2.0.1" + +koa-compose@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" + integrity sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec= + dependencies: + any-promise "^1.1.0" + +koa-compose@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" + integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== + +koa-convert@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" + integrity sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA= + dependencies: + co "^4.6.0" + koa-compose "^3.0.0" + +koa-multer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/koa-multer/-/koa-multer-1.0.2.tgz#d38f7ffd1db97b1aad33e7774732f000ebd67259" + integrity sha512-0kFzN4atVd+9oiG+4fYxQ9S2T3dPhKNvmhITIY606Qn9wLEmfhW0DhSpOzRYhddN//4rh/TCK95TMtflmFa5lA== + dependencies: + multer "1.3.0" + +koa-router@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/koa-router/-/koa-router-7.4.0.tgz#aee1f7adc02d5cb31d7d67465c9eacc825e8c5e0" + integrity sha512-IWhaDXeAnfDBEpWS6hkGdZ1ablgr6Q6pGdXCyK38RbzuH4LkUOpPqPw+3f8l8aTDrQmBQ7xJc0bs2yV4dzcO+g== + dependencies: + debug "^3.1.0" + http-errors "^1.3.1" + koa-compose "^3.0.0" + methods "^1.0.1" + path-to-regexp "^1.1.1" + urijs "^1.19.0" + +koa@^2.8.2: + version "2.13.1" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.1.tgz#6275172875b27bcfe1d454356a5b6b9f5a9b1051" + integrity sha512-Lb2Dloc72auj5vK4X4qqL7B5jyDPQaZucc9sR/71byg7ryoD1NCaCm63CShk9ID9quQvDEi1bGR/iGjCG7As3w== + dependencies: + accepts "^1.3.5" + cache-content-type "^1.0.0" + content-disposition "~0.5.2" + content-type "^1.0.4" + cookies "~0.8.0" + debug "~3.1.0" + delegates "^1.0.0" + depd "^2.0.0" + destroy "^1.0.4" + encodeurl "^1.0.2" + escape-html "^1.0.3" + fresh "~0.5.2" + http-assert "^1.3.0" + http-errors "^1.6.3" + is-generator-function "^1.0.7" + koa-compose "^4.1.0" + koa-convert "^1.2.0" + on-finished "^2.3.0" + only "~0.0.2" + parseurl "^1.3.2" + statuses "^1.5.0" + type-is "^1.6.16" + vary "^1.1.2" + kuler@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" @@ -7995,6 +8284,11 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +libphonenumber-js@^1.9.7: + version "1.9.15" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.15.tgz#d08c533009216c993382c833eaf1639217bd4350" + integrity sha512-gKgvXJmYX00mS+dsy7VUWAsnfKeAyEqGFmDBDor2mtHo08RkceNLQ6PUKS+6h7Tq1SK/4MP2Re8rJ3J0gHmfTA== + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -8133,6 +8427,11 @@ lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= +lodash.groupby@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" + integrity sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E= + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -8199,6 +8498,11 @@ lodash.memoize@4.x, lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= +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" @@ -8477,7 +8781,7 @@ merge2@^1.3.0: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -methods@~1.1.2: +methods@^1.0.1, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= @@ -8680,6 +8984,34 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +multer@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/multer/-/multer-1.3.0.tgz#092b2670f6846fa4914965efc8cf94c20fec6cd2" + integrity sha1-CSsmcPaEb6SRSWXvyM+Uwg/sbNI= + dependencies: + append-field "^0.1.0" + busboy "^0.2.11" + concat-stream "^1.5.0" + mkdirp "^0.5.1" + object-assign "^3.0.0" + on-finished "^2.3.0" + type-is "^1.6.4" + xtend "^4.0.0" + +multer@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a" + integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg== + dependencies: + append-field "^1.0.0" + busboy "^0.2.11" + concat-stream "^1.5.2" + mkdirp "^0.5.1" + object-assign "^4.1.1" + on-finished "^2.3.0" + type-is "^1.6.4" + xtend "^4.0.0" + multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" @@ -8970,6 +9302,11 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= + object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -9078,7 +9415,7 @@ obuf@^1.0.0, obuf@^1.1.2: resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@^2.2.0, on-finished@~2.3.0: +on-finished@^2.2.0, on-finished@^2.3.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= @@ -9118,6 +9455,11 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +only@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= + open@^6.3.0: version "6.4.0" resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" @@ -9130,6 +9472,13 @@ openapi3-ts@^1.2.0: resolved "https://registry.yarnpkg.com/openapi3-ts/-/openapi3-ts-1.4.0.tgz#679d5a24be0efc36f5de4fc2c4b8513663e16f65" integrity sha512-8DmE2oKayvSkIR3XSZ4+pRliBsx19bSNeIzkTPswY8r4wvjX86bMxsORdqwAwMxE8PefOcSAT2auvi/0TZe9yA== +openapi3-ts@^2.0.0, openapi3-ts@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/openapi3-ts/-/openapi3-ts-2.0.1.tgz#b270aecea09e924f1886bc02a72608fca5a98d85" + integrity sha512-v6X3iwddhi276siej96jHGIqTx3wzVfMTmpGJEQDt7GPI7pI6sywItURLzpEci21SBRpPN/aOWSF5mVfFVNmcg== + dependencies: + yaml "^1.10.0" + opencollective-postinstall@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" @@ -9376,7 +9725,7 @@ parse5@5.1.1: resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== -parseurl@~1.3.2, parseurl@~1.3.3: +parseurl@^1.3.2, parseurl@~1.3.2, 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== @@ -9439,13 +9788,18 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= -path-to-regexp@^1.7.0, path-to-regexp@^1.8.0: +path-to-regexp@^1.1.1, path-to-regexp@^1.7.0, path-to-regexp@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== dependencies: isarray "0.0.1" +path-to-regexp@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.4.0.tgz#35ce7f333d5616f1c1e1bfe266c3aba2e5b2e704" + integrity sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w== + path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -10567,6 +10921,13 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@^6.5.2: + version "6.10.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" + integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + dependencies: + side-channel "^1.0.4" + qs@^6.6.0: version "6.9.6" resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" @@ -10587,6 +10948,11 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== +random-bytes@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" + integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= + randomatic@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" @@ -10781,7 +11147,7 @@ readable-stream@1.1.x: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.3.6, readable-stream@^2.3.7, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.6, readable-stream@^2.3.7, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -10858,6 +11224,11 @@ redux@*, redux@^4.0.0, redux@^4.0.5: loose-envify "^1.4.0" symbol-observable "^1.2.0" +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== + refractor@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.3.0.tgz#42a7d58f14a1d1bcda52a8c66123601a71e5d47d" @@ -11194,6 +11565,36 @@ router@^1.3.1: setprototypeof "1.2.0" utils-merge "1.0.1" +routing-controllers-openapi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/routing-controllers-openapi/-/routing-controllers-openapi-3.0.0.tgz#d5506b555e7e8b35cf32ff3cc19243c038a0800a" + integrity sha512-ZsXuQnKEy15ZO3P2rd3ctUdnUTx5cwIO2yGcCD6rEkoclT8ulxUvwHbiFvGU7KoxchttXbrg2j+Hl2Rs4gYmUA== + dependencies: + lodash "^4.17.15" + openapi3-ts "^2.0.1" + path-to-regexp "^2.2.1" + reflect-metadata "^0.1.13" + tslib "^2.1.0" + +routing-controllers@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/routing-controllers/-/routing-controllers-0.9.0.tgz#979016523db37832d4c9a23c33b2654a89a563de" + integrity sha512-OtARLKA6j8enNgGqi/hoRqBsTjVo2hbxc1+MeKi8mvelNn18+LXUdHpzY3z4GbCERBtaj8CwVjcsiQR+2w6ZFg== + dependencies: + cookie "^0.4.0" + express-session "^1.17.1" + glob "^7.1.4" + reflect-metadata "^0.1.13" + template-url "^1.0.0" + optionalDependencies: + body-parser "^1.19.0" + express "^4.17.1" + koa "^2.8.2" + koa-bodyparser "^4.2.1" + koa-multer "^1.0.2" + koa-router "^7.4.0" + multer "^1.4.2" + rsvp@^4.8.4, rsvp@^4.8.5: version "4.8.5" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" @@ -11221,6 +11622,11 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -11514,7 +11920,7 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== -side-channel@^1.0.2, side-channel@^1.0.3: +side-channel@^1.0.2, side-channel@^1.0.3, 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== @@ -11815,7 +12221,7 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@^1.5.0, statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= @@ -11830,6 +12236,11 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== +streamsearch@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" + integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= + string-argv@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -12116,6 +12527,18 @@ svgo@^1.0.0: unquote "~1.1.1" util.promisify "~1.0.0" +swagger-ui-dist@^3.18.1: + version "3.46.0" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.46.0.tgz#f08d2c9b4a2dce922ba363c598e4795b5ccf0b80" + integrity sha512-ueaZ45OHhHvGKmocvCkxFY8VCfbP5PgcxutoQxy9j8/VZeDoLDvg8FBf4SO6NxHhieNAdYPUd0O6G9FjJO2fqw== + +swagger-ui-express@^4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-4.1.6.tgz#682294af3d5c70f74a1fa4d6a9b503a9ee55ea82" + integrity sha512-Xs2BGGudvDBtL7RXcYtNvHsFtP1DBFPMJFRxHe5ez/VG/rzVOEjazJOOSc/kSCyxreCTKfJrII6MJlL9a6t8vw== + dependencies: + swagger-ui-dist "^3.18.1" + symbol-observable@1.2.0, symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -12195,6 +12618,11 @@ tcp-port-used@^1.0.1: debug "4.3.1" is2 "^2.0.6" +template-url@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/template-url/-/template-url-1.0.0.tgz#d9456bee70cac6617b462a7b08db29fb813a0b09" + integrity sha1-2UVr7nDKxmF7Rip7CNsp+4E6Cwk= + term-size@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" @@ -12425,6 +12853,11 @@ triple-beam@^1.2.0, triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== +ts-essentials@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-4.0.0.tgz#506c42b270bbd0465574b90416533175b09205ab" + integrity sha512-uQJX+SRY9mtbKU+g9kl5Fi7AEMofPCvHfJkQlaygpPmHPZrtgaBqbWFOYyiA47RhnSwwnXdepUJrgqUYxoUyhQ== + ts-jest@^26.4.4: version "26.4.4" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.4.4.tgz#61f13fb21ab400853c532270e52cc0ed7e502c49" @@ -12452,6 +12885,16 @@ tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== +tslib@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" + integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== + +tsscmp@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" + integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== + tsutils@^3.17.1: version "3.19.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.19.1.tgz#d8566e0c51c82f32f9c25a4d367cd62409a547a9" @@ -12518,7 +12961,7 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@~1.6.17, type-is@~1.6.18: +type-is@^1.6.16, type-is@^1.6.4, type-is@~1.6.17, 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== @@ -12543,11 +12986,28 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typedi@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/typedi/-/typedi-0.10.0.tgz#e8f9a5ee100b84addbdfb57fe90d8d9ed2a21dea" + integrity sha512-v3UJF8xm68BBj6AF4oQML3ikrfK2c9EmZUyLOfShpJuItAqVBHWP/KtpGinkSsIiP6EZyyb6Z3NXyW9dgS9X1w== + typescript@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== +uid-safe@~2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" + integrity sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA== + dependencies: + random-bytes "~1.0.0" + undefsafe@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" @@ -12689,6 +13149,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +urijs@^1.19.0: + version "1.19.6" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.6.tgz#51f8cb17ca16faefb20b9a31ac60f84aa2b7c870" + integrity sha512-eSXsXZ2jLvGWeLYlQA3Gh36BcjF+0amo92+wHPyN1mdR8Nxf75fuEuYTd9c0a+m/vhCjRK0ESlE9YNLW+E1VEw== + urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -12797,12 +13262,17 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +validator@^13.5.2: + version "13.5.2" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.5.2.tgz#c97ae63ed4224999fb6f42c91eaca9567fe69a46" + integrity sha512-mD45p0rvHVBlY2Zuy3F3ESIe1h5X58GPfAtslBjY7EtTqGquZTj+VX/J4RnHWN8FKq0C9WRVt1oWAcytWRuYLQ== + value-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== -vary@^1, vary@~1.1.2: +vary@^1, vary@^1.1.2, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= @@ -13097,7 +13567,7 @@ winston-transport@^4.4.0: readable-stream "^2.3.7" triple-beam "^1.2.0" -winston@^3.0.0: +winston@^3.0.0, winston@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170" integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw== @@ -13290,6 +13760,11 @@ yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" +ylru@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" + integrity sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"