From c9d6f5a8eaeedbea8318111cee6a05f1faaeb060 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Mon, 17 Jan 2022 14:50:08 -0300 Subject: [PATCH 01/92] first commit --- ormconfig.json | 15 + package.json | 34 + src/shared/errors/AppError.ts | 11 + src/shared/http/routes/index.ts | 9 + src/shared/http/server.ts | 34 + src/shared/typeorm/index.ts | 3 + tsconfig.json | 105 ++ yarn.lock | 1919 +++++++++++++++++++++++++++++++ 8 files changed, 2130 insertions(+) create mode 100644 ormconfig.json create mode 100644 package.json create mode 100644 src/shared/errors/AppError.ts create mode 100644 src/shared/http/routes/index.ts create mode 100644 src/shared/http/server.ts create mode 100644 src/shared/typeorm/index.ts create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/ormconfig.json b/ormconfig.json new file mode 100644 index 0000000..28dca32 --- /dev/null +++ b/ormconfig.json @@ -0,0 +1,15 @@ +{ + "type": "postgres", + "port": 5432, + "host": "localhost", + "username": "postgres", + "password": "root", + "database": "lost-and-found", + "entities": [ + "./src/modules/**/typeorm/entities/*.ts" + ], + "migrations": ["./src/shared/typeorm/migrations/*.ts"], + "cli": { + "migrationsDir": "./src/shared/typeorm/migrations" + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1eb4431 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "api-vendas", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "scripts": { + "start": "ts-node-dev -r tsconfig-paths/register --inspect --transpile-only --ignore-watch node_modules src/shared/http/server.ts", + "typeorm": "ts-node-dev -r tsconfig-paths/register ./node_modules/typeorm/cli", + "lint": "eslint . --ext .ts", + "lint-fix": "eslint . --ext .ts --fix" + }, + "devDependencies": { + "@types/cors": "^2.8.12", + "@types/express": "^4.17.13", + "@types/node": "^17.0.8", + "@typescript-eslint/eslint-plugin": "^5.9.0", + "@typescript-eslint/parser": "^5.9.0", + "eslint": "^8.6.0", + "eslint-config-prettier": "6.15.0", + "eslint-plugin-prettier": "3.2.0", + "prettier": "^2.5.1", + "ts-node-dev": "^1.1.8", + "tsconfig-paths": "^3.12.0", + "typescript": "^4.5.4" + }, + "dependencies": { + "cors": "^2.8.5", + "express": "^4.17.2", + "express-async-errors": "^3.1.1", + "pg": "^8.7.1", + "reflect-metadata": "^0.1.13", + "typeorm": "^0.2.41" + } +} diff --git a/src/shared/errors/AppError.ts b/src/shared/errors/AppError.ts new file mode 100644 index 0000000..4554556 --- /dev/null +++ b/src/shared/errors/AppError.ts @@ -0,0 +1,11 @@ +class AppError { + readonly message: string; + readonly statusCode: number; + + constructor(message: string, statusCode = 400) { + this.message = message; + this.statusCode = statusCode; + } +} + +export { AppError }; diff --git a/src/shared/http/routes/index.ts b/src/shared/http/routes/index.ts new file mode 100644 index 0000000..ffd1913 --- /dev/null +++ b/src/shared/http/routes/index.ts @@ -0,0 +1,9 @@ +import { Router } from 'express'; + +const routes = Router(); + +routes.get('/', (request, response) => { + return response.json({ message: 'Hello World' }); +}); + +export { routes }; diff --git a/src/shared/http/server.ts b/src/shared/http/server.ts new file mode 100644 index 0000000..0ba576f --- /dev/null +++ b/src/shared/http/server.ts @@ -0,0 +1,34 @@ +import 'reflect-metadata'; +import express, { NextFunction, Request, Response } from 'express'; +import cors from 'cors'; +import { routes } from './routes'; +import { AppError } from '@shared/errors/AppError'; +import '@shared/typeorm'; + +const app = express(); + +app.use(cors()); +app.use(express.json()); + +app.use(routes); + +app.use( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + (error: Error, request: Request, response: Response, next: NextFunction) => { + if (error instanceof AppError) { + return response.status(error.statusCode).json({ + status: 'error', + message: error.message, + }); + } + + return response.status(500).json({ + status: 'error', + message: 'Internal server error', + }); + }, +); + +app.listen(3333, () => { + console.log('Server started on port 3333'); +}); diff --git a/src/shared/typeorm/index.ts b/src/shared/typeorm/index.ts new file mode 100644 index 0000000..c6e6a48 --- /dev/null +++ b/src/shared/typeorm/index.ts @@ -0,0 +1,3 @@ +import { createConnection } from 'typeorm'; + +createConnection(); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f67a92c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,105 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "lib": ["es6"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + "rootDir": "src", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "paths": { + "@modules/*": ["src/modules/*"], + "@config/*": ["src/config/*"], + "@shared/*": ["src/shared/*"] + }, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + "outDir": "build", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..c12aff5 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1919 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@eslint/eslintrc@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318" + integrity sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.2.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" + integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@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": + 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" + +"@sqltools/formatter@^1.2.2": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" + integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== + +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/cors@^2.8.12": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== + +"@types/express-serve-static-core@^4.17.18": + version "4.17.27" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.27.tgz#7a776191e47295d2a05962ecbb3a4ce97e38b401" + integrity sha512-e/sVallzUTPdyOTiqi8O8pMdBBphscvI6E4JYaKlja4Lm+zh7UFSSdW5VMkRbhDtmrONqOUHOXRguPsDckzxNA== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@^4.17.13": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" + integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/json-schema@^7.0.9": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + +"@types/node@*", "@types/node@^17.0.8": + version "17.0.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b" + integrity sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg== + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/serve-static@*": + version "1.13.10" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" + integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/strip-bom@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" + integrity sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I= + +"@types/strip-json-comments@0.0.30": + version "0.0.30" + resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" + integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== + +"@types/zen-observable@0.8.3": + version "0.8.3" + resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" + integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== + +"@typescript-eslint/eslint-plugin@^5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.0.tgz#382182d5cb062f52aac54434cfc47c28898c8006" + integrity sha512-qT4lr2jysDQBQOPsCCvpPUZHjbABoTJW8V9ZzIYKHMfppJtpdtzszDYsldwhFxlhvrp7aCHeXD1Lb9M1zhwWwQ== + dependencies: + "@typescript-eslint/experimental-utils" "5.9.0" + "@typescript-eslint/scope-manager" "5.9.0" + "@typescript-eslint/type-utils" "5.9.0" + debug "^4.3.2" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.2.0" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/experimental-utils@5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.9.0.tgz#652762d37d6565ef07af285021b8347b6c79a827" + integrity sha512-ZnLVjBrf26dn7ElyaSKa6uDhqwvAi4jBBmHK1VxuFGPRAxhdi18ubQYSGA7SRiFiES3q9JiBOBHEBStOFkwD2g== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.9.0" + "@typescript-eslint/types" "5.9.0" + "@typescript-eslint/typescript-estree" "5.9.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/parser@^5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.9.0.tgz#fdbb08767a4caa6ca6ccfed5f9ffe9387f0c7d97" + integrity sha512-/6pOPz8yAxEt4PLzgbFRDpZmHnXCeZgPDrh/1DaVKOjvn/UPMlWhbx/gA96xRi2JxY1kBl2AmwVbyROUqys5xQ== + dependencies: + "@typescript-eslint/scope-manager" "5.9.0" + "@typescript-eslint/types" "5.9.0" + "@typescript-eslint/typescript-estree" "5.9.0" + debug "^4.3.2" + +"@typescript-eslint/scope-manager@5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.9.0.tgz#02dfef920290c1dcd7b1999455a3eaae7a1a3117" + integrity sha512-DKtdIL49Qxk2a8icF6whRk7uThuVz4A6TCXfjdJSwOsf+9ree7vgQWcx0KOyCdk0i9ETX666p4aMhrRhxhUkyg== + dependencies: + "@typescript-eslint/types" "5.9.0" + "@typescript-eslint/visitor-keys" "5.9.0" + +"@typescript-eslint/type-utils@5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.9.0.tgz#fd5963ead04bc9b7af9c3a8e534d8d39f1ce5f93" + integrity sha512-uVCb9dJXpBrK1071ri5aEW7ZHdDHAiqEjYznF3HSSvAJXyrkxGOw2Ejibz/q6BXdT8lea8CMI0CzKNFTNI6TEQ== + dependencies: + "@typescript-eslint/experimental-utils" "5.9.0" + debug "^4.3.2" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.9.0.tgz#e5619803e39d24a03b3369506df196355736e1a3" + integrity sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg== + +"@typescript-eslint/typescript-estree@5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.9.0.tgz#0e5c6f03f982931abbfbc3c1b9df5fbf92a3490f" + integrity sha512-kxo3xL2mB7XmiVZcECbaDwYCt3qFXz99tBSuVJR4L/sR7CJ+UNAPrYILILktGj1ppfZ/jNt/cWYbziJUlHl1Pw== + dependencies: + "@typescript-eslint/types" "5.9.0" + "@typescript-eslint/visitor-keys" "5.9.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/visitor-keys@5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz#7585677732365e9d27f1878150fab3922784a1a6" + integrity sha512-6zq0mb7LV0ThExKlecvpfepiB+XEtFv/bzx7/jKSgyXTFD7qjmSu1FoiS0x3OZaiS+UIXpH2vd9O89f02RCtgw== + dependencies: + "@typescript-eslint/types" "5.9.0" + eslint-visitor-keys "^3.0.0" + +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== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + +ajv@^6.10.0, ajv@^6.12.4: + 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.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +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-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" + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +app-root-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" + integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== + +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@^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 sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +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== + +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== + +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== + +body-parser@1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" + integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== + dependencies: + bytes "3.1.1" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.9.6" + raw-body "2.4.2" + type-is "~1.6.18" + +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" + +braces@^3.0.1, 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" + +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@^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" + +bytes@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" + integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== + +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== + +chalk@^4.0.0, chalk@^4.1.0: + 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" + +chokidar@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + 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" + +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" + +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" + +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.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== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +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: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +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== + +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" + +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.2: + 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" + +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.1, debug@^4.3.1, debug@^4.3.2: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +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== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +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@^8.2.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + +dynamic-dedupe@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz#06e44c223f5e4e94d78ef9db23a6515ce2f962a1" + integrity sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE= + dependencies: + xtend "^4.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +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== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +enquirer@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +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 sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +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@6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" + integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw== + dependencies: + get-stdin "^6.0.0" + +eslint-plugin-prettier@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.2.0.tgz#af391b2226fa0e15c96f36c733f6e9035dbd952c" + integrity sha512-kOUSJnFjAUFKwVxuzy6sA5yyMx6+o9ino4gCdShzBNx4eyFRudWRYKCFolKjoM40PEiuU6Cn7wBLfq3WsGg7qg== + dependencies: + prettier-linter-helpers "^1.0.0" + +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.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.0.tgz#c1f6ea30ac583031f203d65c73e723b01298f153" + integrity sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" + integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== + +eslint@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.6.0.tgz#4318c6a31c5584838c1a2e940c478190f58d558e" + integrity sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw== + dependencies: + "@eslint/eslintrc" "^1.0.5" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.0" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.1.0" + espree "^9.3.0" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^6.0.1" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.2.0" + semver "^7.2.1" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^9.2.0, espree@^9.3.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.0.tgz#c1240d79183b72aaee6ccfa5a90bc9111df085a8" + integrity sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ== + dependencies: + acorn "^8.7.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.1.0" + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + 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 sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +express-async-errors@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/express-async-errors/-/express-async-errors-3.1.1.tgz#6053236d61d21ddef4892d6bd1d736889fc9da41" + integrity sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng== + +express@^4.17.2: + version "4.17.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.2.tgz#c18369f265297319beed4e5558753cc8c1364cb3" + integrity sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.4.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.9.6" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.17.2" + serve-static "1.14.2" + setprototypeof "1.2.0" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +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.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-glob@^3.2.9: + version "3.2.9" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.9.tgz#8f55f664b68a236bd29fa165817fc44f2b11faba" + integrity sha512-MBwILhhD92sziIrMQwpqcuGERF+BH99ei2a3XsGJuqEKcSycAL+w0HWokFenZXona+kjFr82Lf71eTxNRC06XQ== + 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.0.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 sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +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" + +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.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" + integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== + +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 sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +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-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== + +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.1: + 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@^7.1.3, glob@^7.1.6: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.6.0, globals@^13.9.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" + integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.4: + 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" + +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@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +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== + +http-errors@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + +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.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@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.8, ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + 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" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +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-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.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +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-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-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== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-yaml@^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" + +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-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 sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +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" + +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== + +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" + +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== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +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: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +mime-db@1.51.0: + version "1.51.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== + +mime-types@~2.1.24: + version "2.1.34" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" + integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + dependencies: + mime-db "1.51.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== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +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: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +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 sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +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== + +object-assign@^4, object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +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= + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +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" + +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-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 sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +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-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-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 sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +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-connection-string@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" + integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== + +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.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.4.1.tgz#0e71ce2c67b442a5e862a9c182172c37eda71e9c" + integrity sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ== + +pg-protocol@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" + integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== + +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.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" + integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.5.0" + pg-pool "^3.4.1" + pg-protocol "^1.5.0" + pg-types "^2.1.0" + pgpass "1.x" + +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" + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +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 sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + +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@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" + integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +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" + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.9.6: + version "6.9.6" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" + integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== + +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== + +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.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" + integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== + dependencies: + bytes "3.1.1" + http-errors "1.8.1" + iconv-lite "0.4.24" + unpipe "1.0.0" + +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" + +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== + +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +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@^1.0.0: + version "1.21.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" + integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== + dependencies: + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +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@^2.6.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +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-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" + +safe-buffer@5.2.1, safe-buffer@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"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== + +sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +semver@^7.2.1, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +send@0.17.2: + version "0.17.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" + integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "1.8.1" + mime "1.6.0" + ms "2.1.3" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.2: + version "1.14.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" + integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.2" + +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== + +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.12, source-map-support@^0.5.17: + 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.6.0: + 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.1.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" + integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +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" + +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-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-json-comments@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +strip-json-comments@^3.1.0, 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== + +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-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== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + 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" + +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== + +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== + +ts-node-dev@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-1.1.8.tgz#95520d8ab9d45fffa854d6668e2f8f9286241066" + integrity sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg== + dependencies: + chokidar "^3.5.1" + dynamic-dedupe "^0.3.0" + minimist "^1.2.5" + mkdirp "^1.0.4" + resolve "^1.0.0" + rimraf "^2.6.1" + source-map-support "^0.5.12" + tree-kill "^1.2.2" + ts-node "^9.0.0" + tsconfig "^7.0.0" + +ts-node@^9.0.0: + version "9.1.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" + integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== + dependencies: + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + +tsconfig-paths@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" + integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + +tsconfig@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" + integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== + dependencies: + "@types/strip-bom" "^3.0.0" + "@types/strip-json-comments" "0.0.30" + strip-bom "^3.0.0" + strip-json-comments "^2.0.0" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +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-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-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" + +typeorm@^0.2.41: + version "0.2.41" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.41.tgz#88758101ac158dc0a0a903d70eaacea2974281cc" + integrity sha512-/d8CLJJxKPgsnrZWiMyPI0rz2MFZnBQrnQ5XP3Vu3mswv2WPexb58QM6BEtmRmlTMYN5KFWUz8SKluze+wS9xw== + dependencies: + "@sqltools/formatter" "^1.2.2" + app-root-path "^3.0.0" + buffer "^6.0.3" + chalk "^4.1.0" + cli-highlight "^2.1.11" + debug "^4.3.1" + dotenv "^8.2.0" + glob "^7.1.6" + js-yaml "^4.0.0" + mkdirp "^1.0.4" + reflect-metadata "^0.1.13" + sha.js "^2.4.11" + tslib "^2.1.0" + xml2js "^0.4.23" + yargs "^17.0.1" + zen-observable-ts "^1.0.0" + +typescript@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" + integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== + +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 sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +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" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +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" + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +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" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +xml2js@^0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + +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: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +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-parser@^21.0.0: + version "21.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" + integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== + +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.0.1: + version "17.3.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" + integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== + dependencies: + cliui "^7.0.2" + 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.0.0" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +zen-observable-ts@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" + integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== + dependencies: + "@types/zen-observable" "0.8.3" + zen-observable "0.8.15" + +zen-observable@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From c7deb60cf6f5c87fa8cc65f16c18d1fba4c640f8 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Mon, 17 Jan 2022 19:30:37 -0300 Subject: [PATCH 02/92] refactor: home folder architecture and refactoring code --- .gitignore | 13 +++++++++++++ ormconfig.example.json | 15 +++++++++++++++ ormconfig.json | 6 +++--- src/@types/expres/index.d.ts | 7 +++++++ src/shared/{ => infra}/http/routes/index.ts | 0 src/shared/{ => infra}/http/server.ts | 0 src/shared/{ => infra}/typeorm/index.ts | 0 7 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 ormconfig.example.json create mode 100644 src/@types/expres/index.d.ts rename src/shared/{ => infra}/http/routes/index.ts (100%) rename src/shared/{ => infra}/http/server.ts (100%) rename src/shared/{ => infra}/typeorm/index.ts (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..49788c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.idea/ +.vscode/ +node_modules/ +build/ +temp/ +.env +coverage +ormconfig.json +dist + +uploads/* +!uploads/.gitkeep +.DS_Store \ No newline at end of file diff --git a/ormconfig.example.json b/ormconfig.example.json new file mode 100644 index 0000000..123a455 --- /dev/null +++ b/ormconfig.example.json @@ -0,0 +1,15 @@ +{ + "type": "postgres", + "port": 5432, + "host": "localhost", + "username": "postgres", + "password": "root", + "database": "lost-and-found", + "entities": [ + "./src/modules/**/infra/typeorm/entities/*.ts" + ], + "migrations": ["./src/shared/infra/typeorm/migrations/*.ts"], + "cli": { + "migrationsDir": "./src/shared/infra/typeorm/migrations" + } +} diff --git a/ormconfig.json b/ormconfig.json index 28dca32..123a455 100644 --- a/ormconfig.json +++ b/ormconfig.json @@ -6,10 +6,10 @@ "password": "root", "database": "lost-and-found", "entities": [ - "./src/modules/**/typeorm/entities/*.ts" + "./src/modules/**/infra/typeorm/entities/*.ts" ], - "migrations": ["./src/shared/typeorm/migrations/*.ts"], + "migrations": ["./src/shared/infra/typeorm/migrations/*.ts"], "cli": { - "migrationsDir": "./src/shared/typeorm/migrations" + "migrationsDir": "./src/shared/infra/typeorm/migrations" } } diff --git a/src/@types/expres/index.d.ts b/src/@types/expres/index.d.ts new file mode 100644 index 0000000..4ce30df --- /dev/null +++ b/src/@types/expres/index.d.ts @@ -0,0 +1,7 @@ +declare namespace Express { + export interface Request { + user: { + id: string; + }; + } +} \ No newline at end of file diff --git a/src/shared/http/routes/index.ts b/src/shared/infra/http/routes/index.ts similarity index 100% rename from src/shared/http/routes/index.ts rename to src/shared/infra/http/routes/index.ts diff --git a/src/shared/http/server.ts b/src/shared/infra/http/server.ts similarity index 100% rename from src/shared/http/server.ts rename to src/shared/infra/http/server.ts diff --git a/src/shared/typeorm/index.ts b/src/shared/infra/typeorm/index.ts similarity index 100% rename from src/shared/typeorm/index.ts rename to src/shared/infra/typeorm/index.ts From 11176b7da7e0067e8f076da79256b58189f76798 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 01:17:47 -0300 Subject: [PATCH 03/92] chore: fixing application start --- package.json | 2 +- src/shared/infra/http/server.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1eb4431..e50957e 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "main": "index.js", "license": "MIT", "scripts": { - "start": "ts-node-dev -r tsconfig-paths/register --inspect --transpile-only --ignore-watch node_modules src/shared/http/server.ts", + "start": "ts-node-dev -r tsconfig-paths/register --inspect --transpile-only --ignore-watch node_modules src/shared/infra/http/server.ts", "typeorm": "ts-node-dev -r tsconfig-paths/register ./node_modules/typeorm/cli", "lint": "eslint . --ext .ts", "lint-fix": "eslint . --ext .ts --fix" diff --git a/src/shared/infra/http/server.ts b/src/shared/infra/http/server.ts index 0ba576f..d13673f 100644 --- a/src/shared/infra/http/server.ts +++ b/src/shared/infra/http/server.ts @@ -3,7 +3,7 @@ import express, { NextFunction, Request, Response } from 'express'; import cors from 'cors'; import { routes } from './routes'; import { AppError } from '@shared/errors/AppError'; -import '@shared/typeorm'; +import '@shared/infra/typeorm'; const app = express(); From ed1d273b40d3295fec1b106f61d86b8d43166069 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 01:31:35 -0300 Subject: [PATCH 04/92] chore: adding user migration --- .../migrations/1642478743972-CreateUser.ts | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts diff --git a/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts b/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts new file mode 100644 index 0000000..13676c7 --- /dev/null +++ b/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts @@ -0,0 +1,58 @@ +import {MigrationInterface, QueryRunner, Table} from "typeorm"; + +export class CreateUser1642478743972 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: 'users', + columns: [ + { + name: 'id', + type: 'uuid', + isPrimary: true, + generationStrategy: 'uuid', + default: 'uuid_generate_v4()' + }, + { + name: 'name', + type: 'varchar', + }, + { + name: 'email', + type: 'varchar', + }, + { + name: 'password', + type: 'varchar', + }, + { + name: 'avatar', + type: 'varchar', + isNullable: true, + }, + { + name: "isAdmin", + type: "boolean", + default: false, + }, + { + name: 'created_at', + type: 'timestamp', + default: 'now()', + }, + { + name: 'updated_at', + type: 'timestamp', + default: 'now()', + }, + ] + }) + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable('users'); + } + +} From c33b4912304d8589d48ddaad4b167c553c487153 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 01:50:25 -0300 Subject: [PATCH 05/92] chore: adding eslint and prettier --- .editorconfig | 12 ++++++++++++ .eslintignore | 4 ++++ .eslintrc | 19 +++++++++++++++++++ .prettierrc | 7 +++++++ package.json | 10 ++++++---- 5 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 .editorconfig create mode 100644 .eslintignore create mode 100644 .eslintrc create mode 100644 .prettierrc diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..53fe054 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = true \ No newline at end of file diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..d890ead --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +node_modules +dist +build +/*.js \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..a10ace6 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,19 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint", + "prettier" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "prettier/@typescript-eslint", + "plugin:prettier/recommended" + ], + "rules": { + "no-console": "warn", + "prettier/prettier": "error" + } +} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..71f2ed3 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "trailingComma": "all", + "singleQuote": true, + "printWidth": 80, + "arrowParens": "avoid" +} diff --git a/package.json b/package.json index e50957e..38531da 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,10 @@ "@types/cors": "^2.8.12", "@types/express": "^4.17.13", "@types/node": "^17.0.8", - "@typescript-eslint/eslint-plugin": "^5.9.0", - "@typescript-eslint/parser": "^5.9.0", - "eslint": "^8.6.0", + "@types/uuid": "^8.3.4", + "@typescript-eslint/eslint-plugin": "^5.10.0", + "@typescript-eslint/parser": "^5.10.0", + "eslint": "^8.7.0", "eslint-config-prettier": "6.15.0", "eslint-plugin-prettier": "3.2.0", "prettier": "^2.5.1", @@ -29,6 +30,7 @@ "express-async-errors": "^3.1.1", "pg": "^8.7.1", "reflect-metadata": "^0.1.13", - "typeorm": "^0.2.41" + "typeorm": "^0.2.41", + "uuid": "^8.3.2" } } From b2b28d4547b2a6a5600526f6a8b044b3741f292d Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 02:05:29 -0300 Subject: [PATCH 06/92] feat: adding entity and interface --- src/modules/users/domain/models/IUser.ts | 11 ++ .../users/infra/typeorm/entities/User.ts | 44 ++++++++ .../migrations/1642478743972-CreateUser.ts | 104 +++++++++--------- 3 files changed, 105 insertions(+), 54 deletions(-) create mode 100644 src/modules/users/domain/models/IUser.ts create mode 100644 src/modules/users/infra/typeorm/entities/User.ts diff --git a/src/modules/users/domain/models/IUser.ts b/src/modules/users/domain/models/IUser.ts new file mode 100644 index 0000000..581a404 --- /dev/null +++ b/src/modules/users/domain/models/IUser.ts @@ -0,0 +1,11 @@ +interface IUser { + id: string; + name: string; + email: string; + password: string; + avatar: string; + created_at: Date; + updated_at: Date; +} + +export { IUser }; diff --git a/src/modules/users/infra/typeorm/entities/User.ts b/src/modules/users/infra/typeorm/entities/User.ts new file mode 100644 index 0000000..ce8aa55 --- /dev/null +++ b/src/modules/users/infra/typeorm/entities/User.ts @@ -0,0 +1,44 @@ +import { IUser } from '@modules/users/domain/models/IUser'; +import { + Column, + CreateDateColumn, + Entity, + PrimaryColumn, + UpdateDateColumn, +} from 'typeorm'; +import { v4 as uuidV4 } from 'uuid'; + +@Entity('users') +class User implements IUser { + @PrimaryColumn() + id: string; + + @Column() + name: string; + + @Column() + email: string; + + @Column() + password: string; + + @Column() + avatar: string; + + @Column() + isAdmin: boolean; + + @CreateDateColumn() + created_at: Date; + + @UpdateDateColumn() + updated_at: Date; + + constructor() { + if (!this.id) { + this.id = uuidV4(); + } + } +} + +export { User }; diff --git a/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts b/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts index 13676c7..aafedd5 100644 --- a/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts +++ b/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts @@ -1,58 +1,54 @@ -import {MigrationInterface, QueryRunner, Table} from "typeorm"; +import { MigrationInterface, QueryRunner, Table } from 'typeorm'; export class CreateUser1642478743972 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: 'users', + columns: [ + { + name: 'id', + type: 'uuid', + isPrimary: true, + }, + { + name: 'name', + type: 'varchar', + }, + { + name: 'email', + type: 'varchar', + }, + { + name: 'password', + type: 'varchar', + }, + { + name: 'avatar', + type: 'varchar', + isNullable: true, + }, + { + name: 'isAdmin', + type: 'boolean', + default: false, + }, + { + name: 'created_at', + type: 'timestamp', + default: 'now()', + }, + { + name: 'updated_at', + type: 'timestamp', + default: 'now()', + }, + ], + }), + ); + } - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.createTable( - new Table({ - name: 'users', - columns: [ - { - name: 'id', - type: 'uuid', - isPrimary: true, - generationStrategy: 'uuid', - default: 'uuid_generate_v4()' - }, - { - name: 'name', - type: 'varchar', - }, - { - name: 'email', - type: 'varchar', - }, - { - name: 'password', - type: 'varchar', - }, - { - name: 'avatar', - type: 'varchar', - isNullable: true, - }, - { - name: "isAdmin", - type: "boolean", - default: false, - }, - { - name: 'created_at', - type: 'timestamp', - default: 'now()', - }, - { - name: 'updated_at', - type: 'timestamp', - default: 'now()', - }, - ] - }) - ) - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('users'); - } - + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable('users'); + } } From 7afd6166bc33bf0b93046d9daac6b766f42921a8 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 03:29:52 -0300 Subject: [PATCH 07/92] feat: creating users --- .../users/domain/dtos/ICreateUserDTO.ts | 9 ++++ .../domain/repositories/IUsersRepository.ts | 10 +++++ .../http/controllers/CreateUserController.ts | 21 +++++++++ .../users/infra/http/routes/users.routes.ts | 10 +++++ .../typeorm/repositories/UsersRepository.ts | 45 +++++++++++++++++++ .../users/services/CreateUserService.ts | 21 +++++++++ src/shared/container/index.ts | 9 ++++ src/shared/infra/http/routes/index.ts | 5 +-- src/shared/infra/http/server.ts | 2 + 9 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 src/modules/users/domain/dtos/ICreateUserDTO.ts create mode 100644 src/modules/users/domain/repositories/IUsersRepository.ts create mode 100644 src/modules/users/infra/http/controllers/CreateUserController.ts create mode 100644 src/modules/users/infra/http/routes/users.routes.ts create mode 100644 src/modules/users/infra/typeorm/repositories/UsersRepository.ts create mode 100644 src/modules/users/services/CreateUserService.ts create mode 100644 src/shared/container/index.ts diff --git a/src/modules/users/domain/dtos/ICreateUserDTO.ts b/src/modules/users/domain/dtos/ICreateUserDTO.ts new file mode 100644 index 0000000..a71b3f0 --- /dev/null +++ b/src/modules/users/domain/dtos/ICreateUserDTO.ts @@ -0,0 +1,9 @@ +interface ICreateUserDTO { + id?: string; + name: string; + email: string; + password: string; + avatar?: string; +} + +export { ICreateUserDTO }; diff --git a/src/modules/users/domain/repositories/IUsersRepository.ts b/src/modules/users/domain/repositories/IUsersRepository.ts new file mode 100644 index 0000000..866f293 --- /dev/null +++ b/src/modules/users/domain/repositories/IUsersRepository.ts @@ -0,0 +1,10 @@ +import { ICreateUserDTO } from '../dtos/ICreateUserDTO'; +import { IUser } from '../models/IUser'; + +interface IUsersRepository { + create(data: ICreateUserDTO): Promise; + findByEmail(email: string): Promise; + findById(id: string): Promise; +} + +export { IUsersRepository }; diff --git a/src/modules/users/infra/http/controllers/CreateUserController.ts b/src/modules/users/infra/http/controllers/CreateUserController.ts new file mode 100644 index 0000000..84ae056 --- /dev/null +++ b/src/modules/users/infra/http/controllers/CreateUserController.ts @@ -0,0 +1,21 @@ +import { CreateUserService } from '@modules/users/services/CreateUserService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class CreateUserController { + async handle(request: Request, response: Response): Promise { + const { name, email, password } = request.body; + + const createUserService = container.resolve(CreateUserService); + + const createUser = await createUserService.execute({ + name, + email, + password, + }); + + return response.status(201).json(createUser); + } +} + +export { CreateUserController }; diff --git a/src/modules/users/infra/http/routes/users.routes.ts b/src/modules/users/infra/http/routes/users.routes.ts new file mode 100644 index 0000000..095ff94 --- /dev/null +++ b/src/modules/users/infra/http/routes/users.routes.ts @@ -0,0 +1,10 @@ +import { Router } from 'express'; +import { CreateUserController } from '../controllers/CreateUserController'; + +const usersRoutes = Router(); + +const createUserController = new CreateUserController(); + +usersRoutes.post('/', createUserController.handle); + +export { usersRoutes }; diff --git a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts new file mode 100644 index 0000000..759505c --- /dev/null +++ b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts @@ -0,0 +1,45 @@ +import { ICreateUserDTO } from '@modules/users/domain/dtos/ICreateUserDTO'; +import { IUser } from '@modules/users/domain/models/IUser'; +import { IUsersRepository } from '@modules/users/domain/repositories/IUsersRepository'; +import { getRepository, Repository } from 'typeorm'; +import { User } from '../entities/User'; + +class UsersRepository implements IUsersRepository { + private repository: Repository; + + constructor() { + this.repository = getRepository(User); + } + + async create({ + id, + name, + email, + password, + avatar, + }: ICreateUserDTO): Promise { + const createUser = this.repository.create({ + id, + name, + email, + password, + avatar, + }); + + await this.repository.save(createUser); + } + + async findByEmail(email: string): Promise { + const user = await this.repository.findOne({ email }); + + return user; + } + + async findById(id: string): Promise { + const user = await this.repository.findOne(id); + + return user; + } +} + +export { UsersRepository }; diff --git a/src/modules/users/services/CreateUserService.ts b/src/modules/users/services/CreateUserService.ts new file mode 100644 index 0000000..2ba437f --- /dev/null +++ b/src/modules/users/services/CreateUserService.ts @@ -0,0 +1,21 @@ +import { inject, injectable } from 'tsyringe'; +import { ICreateUserDTO } from '../domain/dtos/ICreateUserDTO'; +import { IUsersRepository } from '../domain/repositories/IUsersRepository'; + +@injectable() +class CreateUserService { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + ) {} + + async execute({ name, email, password }: ICreateUserDTO): Promise { + await this.usersRepository.create({ + name, + email, + password, + }); + } +} + +export { CreateUserService }; diff --git a/src/shared/container/index.ts b/src/shared/container/index.ts new file mode 100644 index 0000000..5ab6710 --- /dev/null +++ b/src/shared/container/index.ts @@ -0,0 +1,9 @@ +import { IUsersRepository } from '@modules/users/domain/repositories/IUsersRepository'; +import { UsersRepository } from '@modules/users/infra/typeorm/repositories/UsersRepository'; + +import { container } from 'tsyringe'; + +container.registerSingleton( + 'UsersRepository', + UsersRepository, +); diff --git a/src/shared/infra/http/routes/index.ts b/src/shared/infra/http/routes/index.ts index ffd1913..7a343ae 100644 --- a/src/shared/infra/http/routes/index.ts +++ b/src/shared/infra/http/routes/index.ts @@ -1,9 +1,8 @@ +import { usersRoutes } from '@modules/users/infra/http/routes/users.routes'; import { Router } from 'express'; const routes = Router(); -routes.get('/', (request, response) => { - return response.json({ message: 'Hello World' }); -}); +routes.use('/users', usersRoutes); export { routes }; diff --git a/src/shared/infra/http/server.ts b/src/shared/infra/http/server.ts index d13673f..37f31b5 100644 --- a/src/shared/infra/http/server.ts +++ b/src/shared/infra/http/server.ts @@ -3,7 +3,9 @@ import express, { NextFunction, Request, Response } from 'express'; import cors from 'cors'; import { routes } from './routes'; import { AppError } from '@shared/errors/AppError'; + import '@shared/infra/typeorm'; +import '@shared/container'; const app = express(); From 24423313e1ad0d2897def42dab12c9c8e7a1b228 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 03:30:39 -0300 Subject: [PATCH 08/92] chore: adding tsyringe --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 38531da..817af1a 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "express-async-errors": "^3.1.1", "pg": "^8.7.1", "reflect-metadata": "^0.1.13", + "tsyringe": "^4.6.0", "typeorm": "^0.2.41", "uuid": "^8.3.2" } From d78da9b2bfdd8370ace2e772ab63a368ce90faed Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 03:31:30 -0300 Subject: [PATCH 09/92] chore: enabling tsconfig function --- tsconfig.json | 6 +- yarn.lock | 162 +++++++++++++++++++++++++------------------------- 2 files changed, 85 insertions(+), 83 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index f67a92c..4aaf597 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,8 +14,8 @@ "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "lib": ["es6"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ @@ -83,7 +83,7 @@ // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + "strictPropertyInitialization": false, /* Check for class properties that are declared but not set in the constructor. */ // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ diff --git a/yarn.lock b/yarn.lock index c12aff5..98851ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -144,19 +144,24 @@ resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== +"@types/uuid@^8.3.4": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== + "@types/zen-observable@0.8.3": version "0.8.3" resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== -"@typescript-eslint/eslint-plugin@^5.9.0": - version "5.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.9.0.tgz#382182d5cb062f52aac54434cfc47c28898c8006" - integrity sha512-qT4lr2jysDQBQOPsCCvpPUZHjbABoTJW8V9ZzIYKHMfppJtpdtzszDYsldwhFxlhvrp7aCHeXD1Lb9M1zhwWwQ== +"@typescript-eslint/eslint-plugin@^5.10.0": + version "5.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.0.tgz#e90afea96dff8620892ad216b0e4ccdf8ee32d3a" + integrity sha512-XXVKnMsq2fuu9K2KsIxPUGqb6xAImz8MEChClbXmE3VbveFtBUU5bzM6IPVWqzyADIgdkS2Ws/6Xo7W2TeZWjQ== dependencies: - "@typescript-eslint/experimental-utils" "5.9.0" - "@typescript-eslint/scope-manager" "5.9.0" - "@typescript-eslint/type-utils" "5.9.0" + "@typescript-eslint/scope-manager" "5.10.0" + "@typescript-eslint/type-utils" "5.10.0" + "@typescript-eslint/utils" "5.10.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -164,69 +169,69 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@5.9.0": - version "5.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.9.0.tgz#652762d37d6565ef07af285021b8347b6c79a827" - integrity sha512-ZnLVjBrf26dn7ElyaSKa6uDhqwvAi4jBBmHK1VxuFGPRAxhdi18ubQYSGA7SRiFiES3q9JiBOBHEBStOFkwD2g== +"@typescript-eslint/parser@^5.10.0": + version "5.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.10.0.tgz#8f59e036f5f1cffc178cacbd5ccdd02aeb96c91c" + integrity sha512-pJB2CCeHWtwOAeIxv8CHVGJhI5FNyJAIpx5Pt72YkK3QfEzt6qAlXZuyaBmyfOdM62qU0rbxJzNToPTVeJGrQw== dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.9.0" - "@typescript-eslint/types" "5.9.0" - "@typescript-eslint/typescript-estree" "5.9.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/parser@^5.9.0": - version "5.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.9.0.tgz#fdbb08767a4caa6ca6ccfed5f9ffe9387f0c7d97" - integrity sha512-/6pOPz8yAxEt4PLzgbFRDpZmHnXCeZgPDrh/1DaVKOjvn/UPMlWhbx/gA96xRi2JxY1kBl2AmwVbyROUqys5xQ== - dependencies: - "@typescript-eslint/scope-manager" "5.9.0" - "@typescript-eslint/types" "5.9.0" - "@typescript-eslint/typescript-estree" "5.9.0" + "@typescript-eslint/scope-manager" "5.10.0" + "@typescript-eslint/types" "5.10.0" + "@typescript-eslint/typescript-estree" "5.10.0" debug "^4.3.2" -"@typescript-eslint/scope-manager@5.9.0": - version "5.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.9.0.tgz#02dfef920290c1dcd7b1999455a3eaae7a1a3117" - integrity sha512-DKtdIL49Qxk2a8icF6whRk7uThuVz4A6TCXfjdJSwOsf+9ree7vgQWcx0KOyCdk0i9ETX666p4aMhrRhxhUkyg== +"@typescript-eslint/scope-manager@5.10.0": + version "5.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.10.0.tgz#bb5d872e8b9e36203908595507fbc4d3105329cb" + integrity sha512-tgNgUgb4MhqK6DoKn3RBhyZ9aJga7EQrw+2/OiDk5hKf3pTVZWyqBi7ukP+Z0iEEDMF5FDa64LqODzlfE4O/Dg== dependencies: - "@typescript-eslint/types" "5.9.0" - "@typescript-eslint/visitor-keys" "5.9.0" + "@typescript-eslint/types" "5.10.0" + "@typescript-eslint/visitor-keys" "5.10.0" -"@typescript-eslint/type-utils@5.9.0": - version "5.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.9.0.tgz#fd5963ead04bc9b7af9c3a8e534d8d39f1ce5f93" - integrity sha512-uVCb9dJXpBrK1071ri5aEW7ZHdDHAiqEjYznF3HSSvAJXyrkxGOw2Ejibz/q6BXdT8lea8CMI0CzKNFTNI6TEQ== +"@typescript-eslint/type-utils@5.10.0": + version "5.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.10.0.tgz#8524b9479c19c478347a7df216827e749e4a51e5" + integrity sha512-TzlyTmufJO5V886N+hTJBGIfnjQDQ32rJYxPaeiyWKdjsv2Ld5l8cbS7pxim4DeNs62fKzRSt8Q14Evs4JnZyQ== dependencies: - "@typescript-eslint/experimental-utils" "5.9.0" + "@typescript-eslint/utils" "5.10.0" debug "^4.3.2" tsutils "^3.21.0" -"@typescript-eslint/types@5.9.0": - version "5.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.9.0.tgz#e5619803e39d24a03b3369506df196355736e1a3" - integrity sha512-mWp6/b56Umo1rwyGCk8fPIzb9Migo8YOniBGPAQDNC6C52SeyNGN4gsVwQTAR+RS2L5xyajON4hOLwAGwPtUwg== +"@typescript-eslint/types@5.10.0": + version "5.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.10.0.tgz#beb3cb345076f5b088afe996d57bcd1dfddaa75c" + integrity sha512-wUljCgkqHsMZbw60IbOqT/puLfyqqD5PquGiBo1u1IS3PLxdi3RDGlyf032IJyh+eQoGhz9kzhtZa+VC4eWTlQ== -"@typescript-eslint/typescript-estree@5.9.0": - version "5.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.9.0.tgz#0e5c6f03f982931abbfbc3c1b9df5fbf92a3490f" - integrity sha512-kxo3xL2mB7XmiVZcECbaDwYCt3qFXz99tBSuVJR4L/sR7CJ+UNAPrYILILktGj1ppfZ/jNt/cWYbziJUlHl1Pw== +"@typescript-eslint/typescript-estree@5.10.0": + version "5.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.0.tgz#4be24a3dea0f930bb1397c46187d0efdd955a224" + integrity sha512-x+7e5IqfwLwsxTdliHRtlIYkgdtYXzE0CkFeV6ytAqq431ZyxCFzNMNR5sr3WOlIG/ihVZr9K/y71VHTF/DUQA== dependencies: - "@typescript-eslint/types" "5.9.0" - "@typescript-eslint/visitor-keys" "5.9.0" + "@typescript-eslint/types" "5.10.0" + "@typescript-eslint/visitor-keys" "5.10.0" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/visitor-keys@5.9.0": - version "5.9.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz#7585677732365e9d27f1878150fab3922784a1a6" - integrity sha512-6zq0mb7LV0ThExKlecvpfepiB+XEtFv/bzx7/jKSgyXTFD7qjmSu1FoiS0x3OZaiS+UIXpH2vd9O89f02RCtgw== +"@typescript-eslint/utils@5.10.0": + version "5.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.10.0.tgz#c3d152a85da77c400e37281355561c72fb1b5a65" + integrity sha512-IGYwlt1CVcFoE2ueW4/ioEwybR60RAdGeiJX/iDAw0t5w0wK3S7QncDwpmsM70nKgGTuVchEWB8lwZwHqPAWRg== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.10.0" + "@typescript-eslint/types" "5.10.0" + "@typescript-eslint/typescript-estree" "5.10.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.10.0": + version "5.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.0.tgz#770215497ad67cd15a572b52089991d5dfe06281" + integrity sha512-GMxj0K1uyrFLPKASLmZzCuSddmjZVbVj3Ouy5QVuIGKZopxvOr24JsS7gruz6C3GExE01mublZ3mIBOaon9zuQ== dependencies: - "@typescript-eslint/types" "5.9.0" + "@typescript-eslint/types" "5.10.0" eslint-visitor-keys "^3.0.0" accepts@~1.3.7: @@ -257,11 +262,6 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -566,13 +566,6 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -635,10 +628,15 @@ eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz#eee4acea891814cda67a7d8812d9647dd0179af2" integrity sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA== -eslint@^8.6.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.6.0.tgz#4318c6a31c5584838c1a2e940c478190f58d558e" - integrity sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw== +eslint-visitor-keys@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz#6fbb166a6798ee5991358bc2daa1ba76cc1254a1" + integrity sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ== + +eslint@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.7.0.tgz#22e036842ee5b7cf87b03fe237731675b4d3633c" + integrity sha512-ifHYzkBGrzS2iDU7KjhCAVMGCvF6M3Xfs8X8b37cgrUlDt6bWRTpRh6T/gtSXv1HJ/BUGgmjvNvOEGu85Iif7w== dependencies: "@eslint/eslintrc" "^1.0.5" "@humanwhocodes/config-array" "^0.9.2" @@ -647,11 +645,10 @@ eslint@^8.6.0: cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" escape-string-regexp "^4.0.0" eslint-scope "^7.1.0" eslint-utils "^3.0.0" - eslint-visitor-keys "^3.1.0" + eslint-visitor-keys "^3.2.0" espree "^9.3.0" esquery "^1.4.0" esutils "^2.0.2" @@ -660,7 +657,7 @@ eslint@^8.6.0: functional-red-black-tree "^1.0.1" glob-parent "^6.0.1" globals "^13.6.0" - ignore "^4.0.6" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" @@ -671,9 +668,7 @@ eslint@^8.6.0: minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" - progress "^2.0.0" regexpp "^3.2.0" - semver "^7.2.1" strip-ansi "^6.0.1" strip-json-comments "^3.1.0" text-table "^0.2.0" @@ -1383,11 +1378,6 @@ prettier@^2.5.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -1503,7 +1493,7 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -semver@^7.2.1, semver@^7.3.5: +semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== @@ -1719,7 +1709,7 @@ tsconfig@^7.0.0: strip-bom "^3.0.0" strip-json-comments "^2.0.0" -tslib@^1.8.1: +tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -1736,6 +1726,13 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" +tsyringe@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/tsyringe/-/tsyringe-4.6.0.tgz#14915d3d7f0db35e1cf7269bdbf7c440713c8d07" + integrity sha512-BMQAZamSfEmIQzH8WJeRu1yZGQbPSDuI9g+yEiKZFIcO46GPZuMOC2d0b52cVBdw1d++06JnDSIIZvEnogMdAw== + dependencies: + tslib "^1.9.3" + 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" @@ -1800,6 +1797,11 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" From e517f66302be36650944f0885a087254f82bdf85 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 03:44:19 -0300 Subject: [PATCH 10/92] feat: user creation validation --- src/modules/users/infra/http/routes/users.routes.ts | 13 ++++++++++++- src/shared/infra/http/server.ts | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/modules/users/infra/http/routes/users.routes.ts b/src/modules/users/infra/http/routes/users.routes.ts index 095ff94..64c89dd 100644 --- a/src/modules/users/infra/http/routes/users.routes.ts +++ b/src/modules/users/infra/http/routes/users.routes.ts @@ -1,3 +1,4 @@ +import { celebrate, Segments, Joi } from 'celebrate'; import { Router } from 'express'; import { CreateUserController } from '../controllers/CreateUserController'; @@ -5,6 +6,16 @@ const usersRoutes = Router(); const createUserController = new CreateUserController(); -usersRoutes.post('/', createUserController.handle); +usersRoutes.post( + '/', + celebrate({ + [Segments.BODY]: { + name: Joi.string().required(), + email: Joi.string().required().email(), + password: Joi.string().required().min(6).max(18), + }, + }), + createUserController.handle, +); export { usersRoutes }; diff --git a/src/shared/infra/http/server.ts b/src/shared/infra/http/server.ts index 37f31b5..520dbd2 100644 --- a/src/shared/infra/http/server.ts +++ b/src/shared/infra/http/server.ts @@ -1,6 +1,7 @@ import 'reflect-metadata'; import express, { NextFunction, Request, Response } from 'express'; import cors from 'cors'; +import { errors } from 'celebrate'; import { routes } from './routes'; import { AppError } from '@shared/errors/AppError'; @@ -11,9 +12,10 @@ const app = express(); app.use(cors()); app.use(express.json()); - app.use(routes); +app.use(errors()); + app.use( // eslint-disable-next-line @typescript-eslint/no-unused-vars (error: Error, request: Request, response: Response, next: NextFunction) => { From 7ec97fee1bf812f6e82a2cae231da41a4e666037 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 03:44:37 -0300 Subject: [PATCH 11/92] chore: adding celebrate --- package.json | 2 ++ yarn.lock | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 817af1a..c625448 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "devDependencies": { "@types/cors": "^2.8.12", "@types/express": "^4.17.13", + "@types/joi": "^17.2.3", "@types/node": "^17.0.8", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.10.0", @@ -25,6 +26,7 @@ "typescript": "^4.5.4" }, "dependencies": { + "celebrate": "^15.0.0", "cors": "^2.8.5", "express": "^4.17.2", "express-async-errors": "^3.1.1", diff --git a/yarn.lock b/yarn.lock index 98851ef..6f424c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,6 +17,18 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@hapi/hoek@^9.0.0": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" + integrity sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw== + +"@hapi/topo@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + "@humanwhocodes/config-array@^0.9.2": version "0.9.2" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914" @@ -52,6 +64,23 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@sideway/address@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" + integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + "@sqltools/formatter@^1.2.2": version "1.2.3" resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" @@ -96,6 +125,13 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/joi@^17.2.3": + version "17.2.3" + resolved "https://registry.yarnpkg.com/@types/joi/-/joi-17.2.3.tgz#b7768ed9d84f1ebd393328b9f97c1cf3d2b94798" + integrity sha512-dGjs/lhrWOa+eO0HwgxCSnDm5eMGCsXuvLglMghJq32F6q5LyyNuXb41DHzrg501CKNOSSAHmfB7FDGeUnDmzw== + dependencies: + joi "*" + "@types/json-schema@^7.0.9": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" @@ -386,6 +422,15 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +celebrate@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/celebrate/-/celebrate-15.0.0.tgz#2651237146ea03600d0d1244478782c06270d243" + integrity sha512-eGA5CHv5GYbV6ZaBEYKIST+7OUsHZKcyiNdagdVDu6uO1QK2i2qLrS9XWdJ1pWPuw9M0D7B1rUFQqIld1nNcMA== + dependencies: + escape-html "1.0.3" + joi "17.x.x" + lodash "4.17.x" + chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -571,7 +616,7 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -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= @@ -1043,6 +1088,17 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +joi@*, joi@17.x.x: + version "17.5.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.5.0.tgz#7e66d0004b5045d971cf416a55fb61d33ac6e011" + integrity sha512-R7hR50COp7StzLnDi4ywOXHrBrgNXuUUfJWIR5lPY5Bm/pOD3jZaTwpluUXVLRWcoWZxkrHBBJ5hLxgnlehbdw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + js-yaml@^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" @@ -1080,6 +1136,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash@4.17.x: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" From 3a90b297edefd1ef21cd3b2407484e53a40cef03 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 04:52:11 -0300 Subject: [PATCH 12/92] feat: bcrypt hash providers --- .../providers/implementations/BcryptHashProvider.ts | 13 +++++++++++++ src/modules/users/providers/index.ts | 5 +++++ src/modules/users/providers/models/IHashProvider.ts | 6 ++++++ 3 files changed, 24 insertions(+) create mode 100644 src/modules/users/providers/implementations/BcryptHashProvider.ts create mode 100644 src/modules/users/providers/index.ts create mode 100644 src/modules/users/providers/models/IHashProvider.ts diff --git a/src/modules/users/providers/implementations/BcryptHashProvider.ts b/src/modules/users/providers/implementations/BcryptHashProvider.ts new file mode 100644 index 0000000..fd7f4b1 --- /dev/null +++ b/src/modules/users/providers/implementations/BcryptHashProvider.ts @@ -0,0 +1,13 @@ +import { compare, hash } from 'bcrypt'; +import { IHashProvider } from '../models/IHashProvider'; + +class BcryptHashProvider implements IHashProvider { + generateHash(payload: string): Promise { + return hash(payload, 8); + } + compareHash(payload: string, hashed: string): Promise { + return compare(payload, hashed); + } +} + +export { BcryptHashProvider }; diff --git a/src/modules/users/providers/index.ts b/src/modules/users/providers/index.ts new file mode 100644 index 0000000..509204c --- /dev/null +++ b/src/modules/users/providers/index.ts @@ -0,0 +1,5 @@ +import { container } from 'tsyringe'; +import { BcryptHashProvider } from './implementations/BcryptHashProvider'; +import { IHashProvider } from './models/IHashProvider'; + +container.registerSingleton('HashProvider', BcryptHashProvider); diff --git a/src/modules/users/providers/models/IHashProvider.ts b/src/modules/users/providers/models/IHashProvider.ts new file mode 100644 index 0000000..8ac39f4 --- /dev/null +++ b/src/modules/users/providers/models/IHashProvider.ts @@ -0,0 +1,6 @@ +interface IHashProvider { + generateHash(payload: string): Promise; + compareHash(payload: string, hashed: string): Promise; +} + +export { IHashProvider }; From f457fbb43543fdafb9a6c8ddb8f9326c788cbaff Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 04:52:42 -0300 Subject: [PATCH 13/92] chore: adding bcrypt --- package.json | 2 + yarn.lock | 251 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 247 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index c625448..bd7cdb7 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "lint-fix": "eslint . --ext .ts --fix" }, "devDependencies": { + "@types/bcrypt": "^5.0.0", "@types/cors": "^2.8.12", "@types/express": "^4.17.13", "@types/joi": "^17.2.3", @@ -26,6 +27,7 @@ "typescript": "^4.5.4" }, "dependencies": { + "bcrypt": "^5.0.1", "celebrate": "^15.0.0", "cors": "^2.8.5", "express": "^4.17.2", diff --git a/yarn.lock b/yarn.lock index 6f424c0..e9c0f98 100644 --- a/yarn.lock +++ b/yarn.lock @@ -43,6 +43,21 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz#32abc8a5c624bc4e46c43d84dfb8b26d33a96f58" + integrity sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg== + dependencies: + detect-libc "^1.0.3" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.5" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + "@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" @@ -86,6 +101,13 @@ resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== +"@types/bcrypt@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-5.0.0.tgz#a835afa2882d165aff5690893db314eaa98b9f20" + integrity sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw== + dependencies: + "@types/node" "*" + "@types/body-parser@*": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -270,6 +292,11 @@ "@typescript-eslint/types" "5.10.0" eslint-visitor-keys "^3.0.0" +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -288,6 +315,13 @@ acorn@^8.7.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -328,6 +362,19 @@ app-root-path@^3.0.0: resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -358,6 +405,14 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bcrypt@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.0.1.tgz#f1a2c20f208e2ccdceea4433df0c8b2c54ecdf71" + integrity sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + node-addon-api "^3.1.0" + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" @@ -454,6 +509,11 @@ chokidar@^3.5.1: optionalDependencies: fsevents "~2.3.2" +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + cli-highlight@^2.1.11: version "2.1.11" resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" @@ -487,11 +547,21 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +console-control-strings@^1.0.0, console-control-strings@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -543,7 +613,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: +debug@4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== @@ -555,6 +625,11 @@ deep-is@^0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -565,6 +640,11 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -891,6 +971,13 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -911,6 +998,21 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + 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" @@ -971,6 +1073,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-unicode@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -994,6 +1101,14 @@ http-errors@1.8.1: statuses ">= 1.5.0 < 2" toidentifier "1.0.1" +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1037,7 +1152,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1: +inherits@2, inherits@2.0.4, inherits@^2.0.1, 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== @@ -1148,6 +1263,13 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -1210,7 +1332,22 @@ minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -mkdirp@^1.0.4: +minipass@^3.0.0: + version "3.1.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" + integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -1249,12 +1386,41 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +node-addon-api@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-fetch@^2.6.5: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + 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== -object-assign@^4, object-assign@^4.0.1: +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.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 sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -1477,6 +1643,15 @@ raw-body@2.4.2: iconv-lite "0.4.24" unpipe "1.0.0" +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + 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" @@ -1539,7 +1714,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@5.2.1, safe-buffer@^5.0.1: +safe-buffer@5.2.1, safe-buffer@^5.0.1, 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== @@ -1554,6 +1729,11 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +semver@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" @@ -1590,6 +1770,11 @@ serve-static@1.14.2: parseurl "~1.3.3" send "0.17.2" +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" @@ -1615,6 +1800,11 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +signal-exit@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -1643,7 +1833,7 @@ split2@^4.1.0: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width@^1.0.2 || 2 || 3 || 4", 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== @@ -1652,6 +1842,13 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.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" + 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" @@ -1686,6 +1883,18 @@ supports-preserve-symlinks-flag@^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== +tar@^6.1.11: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -1717,6 +1926,11 @@ toidentifier@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 sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -1853,6 +2067,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -1873,6 +2092,19 @@ vary@^1, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + 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" @@ -1880,6 +2112,13 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wide-align@^1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" From 55e9f312abab4abd4bda2dd4210979b33de7ff7a Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 13:27:56 -0300 Subject: [PATCH 14/92] feat: encrypting user password --- src/modules/users/services/CreateUserService.ts | 14 +++++++++++++- src/shared/container/index.ts | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/modules/users/services/CreateUserService.ts b/src/modules/users/services/CreateUserService.ts index 2ba437f..c171c88 100644 --- a/src/modules/users/services/CreateUserService.ts +++ b/src/modules/users/services/CreateUserService.ts @@ -1,19 +1,31 @@ +import { AppError } from '@shared/errors/AppError'; import { inject, injectable } from 'tsyringe'; import { ICreateUserDTO } from '../domain/dtos/ICreateUserDTO'; import { IUsersRepository } from '../domain/repositories/IUsersRepository'; +import { IHashProvider } from '../providers/models/IHashProvider'; @injectable() class CreateUserService { constructor( @inject('UsersRepository') private usersRepository: IUsersRepository, + @inject('HashProvider') + private hashProvider: IHashProvider, ) {} async execute({ name, email, password }: ICreateUserDTO): Promise { + const emailExists = await this.usersRepository.findByEmail(email); + + if (emailExists) { + throw new AppError('Email address already used.'); + } + + const hashdPassword = await this.hashProvider.generateHash(password); + await this.usersRepository.create({ name, email, - password, + password: hashdPassword, }); } } diff --git a/src/shared/container/index.ts b/src/shared/container/index.ts index 5ab6710..8a462b2 100644 --- a/src/shared/container/index.ts +++ b/src/shared/container/index.ts @@ -2,6 +2,7 @@ import { IUsersRepository } from '@modules/users/domain/repositories/IUsersRepos import { UsersRepository } from '@modules/users/infra/typeorm/repositories/UsersRepository'; import { container } from 'tsyringe'; +import '@modules/users/providers'; container.registerSingleton( 'UsersRepository', From b8dd92175504de3f83277df3af819c01af5b7994 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 13:28:35 -0300 Subject: [PATCH 15/92] chore: adding expres async errors --- src/shared/infra/http/server.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/infra/http/server.ts b/src/shared/infra/http/server.ts index 520dbd2..f3bf2f8 100644 --- a/src/shared/infra/http/server.ts +++ b/src/shared/infra/http/server.ts @@ -1,5 +1,6 @@ import 'reflect-metadata'; import express, { NextFunction, Request, Response } from 'express'; +import 'express-async-errors'; import cors from 'cors'; import { errors } from 'celebrate'; import { routes } from './routes'; From fb03e18d321a08ca205c1fcce76e2fd96421b1bd Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 14:26:22 -0300 Subject: [PATCH 16/92] feat: user authentication --- .../controllers/CreateSessionController.ts | 20 +++++++++ .../infra/http/routes/sessions.routes.ts | 20 +++++++++ .../users/services/CreateSessionService.ts | 41 +++++++++++++++++++ src/shared/infra/http/routes/index.ts | 2 + 4 files changed, 83 insertions(+) create mode 100644 src/modules/users/infra/http/controllers/CreateSessionController.ts create mode 100644 src/modules/users/infra/http/routes/sessions.routes.ts create mode 100644 src/modules/users/services/CreateSessionService.ts diff --git a/src/modules/users/infra/http/controllers/CreateSessionController.ts b/src/modules/users/infra/http/controllers/CreateSessionController.ts new file mode 100644 index 0000000..5baaeb6 --- /dev/null +++ b/src/modules/users/infra/http/controllers/CreateSessionController.ts @@ -0,0 +1,20 @@ +import { CreateSessionService } from '@modules/users/services/CreateSessionService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class CreateSessionController { + async handle(request: Request, response: Response): Promise { + const { email, password } = request.body; + + const createSessionService = container.resolve(CreateSessionService); + + const user = await createSessionService.execute({ + email, + password, + }); + + return response.status(200).json(user); + } +} + +export { CreateSessionController }; diff --git a/src/modules/users/infra/http/routes/sessions.routes.ts b/src/modules/users/infra/http/routes/sessions.routes.ts new file mode 100644 index 0000000..6da4713 --- /dev/null +++ b/src/modules/users/infra/http/routes/sessions.routes.ts @@ -0,0 +1,20 @@ +import { celebrate, Segments, Joi } from 'celebrate'; +import { Router } from 'express'; +import { CreateSessionController } from '../controllers/CreateSessionController'; + +const sessionsRoutes = Router(); + +const createSessionController = new CreateSessionController(); + +sessionsRoutes.post( + '/', + celebrate({ + [Segments.BODY]: { + email: Joi.string().required().email(), + password: Joi.string().required().min(6).max(18), + }, + }), + createSessionController.handle, +); + +export { sessionsRoutes }; diff --git a/src/modules/users/services/CreateSessionService.ts b/src/modules/users/services/CreateSessionService.ts new file mode 100644 index 0000000..306ade4 --- /dev/null +++ b/src/modules/users/services/CreateSessionService.ts @@ -0,0 +1,41 @@ +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { IUser } from '../domain/models/IUser'; +import { IUsersRepository } from '../domain/repositories/IUsersRepository'; +import { IHashProvider } from '../providers/models/IHashProvider'; + +interface IRequest { + email: string; + password: string; +} + +@injectable() +class CreateSessionService { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + @inject('HashProvider') + private hashProvider: IHashProvider, + ) {} + + async execute({ email, password }: IRequest): Promise { + const user = await this.usersRepository.findByEmail(email); + + if (!user) { + throw new AppError('Email or password incorrect.', 401); + } + + const passwordMatch = await this.hashProvider.compareHash( + password, + user.password, + ); + + if (!passwordMatch) { + throw new AppError('Email or password incorrect.', 401); + } + + return user; + } +} + +export { CreateSessionService }; diff --git a/src/shared/infra/http/routes/index.ts b/src/shared/infra/http/routes/index.ts index 7a343ae..cb8cb75 100644 --- a/src/shared/infra/http/routes/index.ts +++ b/src/shared/infra/http/routes/index.ts @@ -1,8 +1,10 @@ +import { sessionsRoutes } from '@modules/users/infra/http/routes/sessions.routes'; import { usersRoutes } from '@modules/users/infra/http/routes/users.routes'; import { Router } from 'express'; const routes = Router(); routes.use('/users', usersRoutes); +routes.use('/sessions', sessionsRoutes); export { routes }; From 4d25426d8d15bba6ddda9632955c5d27dd92f0cd Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 14:28:29 -0300 Subject: [PATCH 17/92] refactor: refactoring and changing user creation --- src/modules/users/domain/dtos/ICreateUserDTO.ts | 2 -- .../users/domain/repositories/IUsersRepository.ts | 2 +- .../infra/typeorm/repositories/UsersRepository.ts | 12 +++--------- src/modules/users/services/CreateUserService.ts | 7 +++++-- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/modules/users/domain/dtos/ICreateUserDTO.ts b/src/modules/users/domain/dtos/ICreateUserDTO.ts index a71b3f0..f90fbd3 100644 --- a/src/modules/users/domain/dtos/ICreateUserDTO.ts +++ b/src/modules/users/domain/dtos/ICreateUserDTO.ts @@ -1,9 +1,7 @@ interface ICreateUserDTO { - id?: string; name: string; email: string; password: string; - avatar?: string; } export { ICreateUserDTO }; diff --git a/src/modules/users/domain/repositories/IUsersRepository.ts b/src/modules/users/domain/repositories/IUsersRepository.ts index 866f293..6e2bcac 100644 --- a/src/modules/users/domain/repositories/IUsersRepository.ts +++ b/src/modules/users/domain/repositories/IUsersRepository.ts @@ -2,7 +2,7 @@ import { ICreateUserDTO } from '../dtos/ICreateUserDTO'; import { IUser } from '../models/IUser'; interface IUsersRepository { - create(data: ICreateUserDTO): Promise; + create(data: ICreateUserDTO): Promise; findByEmail(email: string): Promise; findById(id: string): Promise; } diff --git a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts index 759505c..20aa96d 100644 --- a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts +++ b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts @@ -11,22 +11,16 @@ class UsersRepository implements IUsersRepository { this.repository = getRepository(User); } - async create({ - id, - name, - email, - password, - avatar, - }: ICreateUserDTO): Promise { + async create({ name, email, password }: ICreateUserDTO): Promise { const createUser = this.repository.create({ - id, name, email, password, - avatar, }); await this.repository.save(createUser); + + return createUser; } async findByEmail(email: string): Promise { diff --git a/src/modules/users/services/CreateUserService.ts b/src/modules/users/services/CreateUserService.ts index c171c88..3e1335b 100644 --- a/src/modules/users/services/CreateUserService.ts +++ b/src/modules/users/services/CreateUserService.ts @@ -1,6 +1,7 @@ import { AppError } from '@shared/errors/AppError'; import { inject, injectable } from 'tsyringe'; import { ICreateUserDTO } from '../domain/dtos/ICreateUserDTO'; +import { IUser } from '../domain/models/IUser'; import { IUsersRepository } from '../domain/repositories/IUsersRepository'; import { IHashProvider } from '../providers/models/IHashProvider'; @@ -13,7 +14,7 @@ class CreateUserService { private hashProvider: IHashProvider, ) {} - async execute({ name, email, password }: ICreateUserDTO): Promise { + async execute({ name, email, password }: ICreateUserDTO): Promise { const emailExists = await this.usersRepository.findByEmail(email); if (emailExists) { @@ -22,11 +23,13 @@ class CreateUserService { const hashdPassword = await this.hashProvider.generateHash(password); - await this.usersRepository.create({ + const user = await this.usersRepository.create({ name, email, password: hashdPassword, }); + + return user; } } From c8677b2d9edd3613acfa9748f0bdbc3c7c34fe6e Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 14:52:29 -0300 Subject: [PATCH 18/92] feat: user authentication session with jwt token --- src/config/auth.ts | 6 ++++ .../users/services/CreateSessionService.ts | 30 +++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 src/config/auth.ts diff --git a/src/config/auth.ts b/src/config/auth.ts new file mode 100644 index 0000000..691c7ca --- /dev/null +++ b/src/config/auth.ts @@ -0,0 +1,6 @@ +export default { + jwt: { + secret: '91cf4aa79dbb713fbf551ce3efa9c12d', + expiresIn: '1d', + }, +}; diff --git a/src/modules/users/services/CreateSessionService.ts b/src/modules/users/services/CreateSessionService.ts index 306ade4..9803529 100644 --- a/src/modules/users/services/CreateSessionService.ts +++ b/src/modules/users/services/CreateSessionService.ts @@ -1,6 +1,7 @@ +import authConfig from '@config/auth'; import { AppError } from '@shared/errors/AppError'; +import { sign } from 'jsonwebtoken'; import { inject, injectable } from 'tsyringe'; -import { IUser } from '../domain/models/IUser'; import { IUsersRepository } from '../domain/repositories/IUsersRepository'; import { IHashProvider } from '../providers/models/IHashProvider'; @@ -9,6 +10,15 @@ interface IRequest { password: string; } +interface IResponse { + user: { + name: string; + email: string; + }; + + token: string; +} + @injectable() class CreateSessionService { constructor( @@ -18,7 +28,7 @@ class CreateSessionService { private hashProvider: IHashProvider, ) {} - async execute({ email, password }: IRequest): Promise { + async execute({ email, password }: IRequest): Promise { const user = await this.usersRepository.findByEmail(email); if (!user) { @@ -34,7 +44,21 @@ class CreateSessionService { throw new AppError('Email or password incorrect.', 401); } - return user; + const token = sign({}, authConfig.jwt.secret, { + subject: user.id, + expiresIn: authConfig.jwt.expiresIn, + }); + + const returnToken = { + user: { + name: user.name, + email: user.email, + }, + + token, + }; + + return returnToken; } } From 57d0dd2d9a17a19a9bf2c4dcc56973905941b626 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 14:53:01 -0300 Subject: [PATCH 19/92] chore: adding jsonwebtoken --- package.json | 2 ++ yarn.lock | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index bd7cdb7..d9edcfb 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@types/cors": "^2.8.12", "@types/express": "^4.17.13", "@types/joi": "^17.2.3", + "@types/jsonwebtoken": "^8.5.8", "@types/node": "^17.0.8", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.10.0", @@ -32,6 +33,7 @@ "cors": "^2.8.5", "express": "^4.17.2", "express-async-errors": "^3.1.1", + "jsonwebtoken": "^8.5.1", "pg": "^8.7.1", "reflect-metadata": "^0.1.13", "tsyringe": "^4.6.0", diff --git a/yarn.lock b/yarn.lock index e9c0f98..e8c426f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -164,6 +164,13 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/jsonwebtoken@^8.5.8": + version "8.5.8" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz#01b39711eb844777b7af1d1f2b4cf22fda1c0c44" + integrity sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A== + dependencies: + "@types/node" "*" + "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" @@ -449,6 +456,11 @@ braces@^3.0.1, braces@~3.0.2: dependencies: fill-range "^7.0.1" +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 sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -676,6 +688,13 @@ dynamic-dedupe@^0.3.0: dependencies: xtend "^4.0.0" +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" @@ -1238,6 +1257,39 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + 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 "^5.6.0" + +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" + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1246,11 +1298,46 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.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 sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + 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 sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + lodash@4.17.x: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -1362,7 +1449,7 @@ ms@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.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== @@ -1729,6 +1816,11 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + semver@^6.0.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" From 190431ad0521f525813342ece8ae75a4af766c0b Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 17:44:49 -0300 Subject: [PATCH 20/92] feat: user authentication middleware --- src/@types/expres/index.d.ts | 2 +- .../http/middlewares/ensureAuthenticated.ts | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/shared/infra/http/middlewares/ensureAuthenticated.ts diff --git a/src/@types/expres/index.d.ts b/src/@types/expres/index.d.ts index 4ce30df..4dda62f 100644 --- a/src/@types/expres/index.d.ts +++ b/src/@types/expres/index.d.ts @@ -4,4 +4,4 @@ declare namespace Express { id: string; }; } -} \ No newline at end of file +} diff --git a/src/shared/infra/http/middlewares/ensureAuthenticated.ts b/src/shared/infra/http/middlewares/ensureAuthenticated.ts new file mode 100644 index 0000000..ed882d0 --- /dev/null +++ b/src/shared/infra/http/middlewares/ensureAuthenticated.ts @@ -0,0 +1,34 @@ +import { AppError } from '@shared/errors/AppError'; +import { NextFunction, Request, Response } from 'express'; +import { verify } from 'jsonwebtoken'; +import authConfig from '@config/auth'; + +interface IPayload { + sub: string; +} + +export default function ensureAuthenticated( + request: Request, + response: Response, + next: NextFunction, +): void { + const authHeader = request.headers.authorization; + + if (!authHeader) { + throw new AppError('JWT Token is missing.', 401); + } + + const [, token] = authHeader.split(' '); + + try { + const { sub: user_id } = verify(token, authConfig.jwt.secret) as IPayload; + + request.user = { + id: user_id, + }; + + next(); + } catch (err) { + throw new AppError('Invalid JWT Token.', 401); + } +} From 864f17e1b725ef6f21777b82ceee98e192837b03 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 17:46:32 -0300 Subject: [PATCH 21/92] feat: list of all users --- .../domain/repositories/IUsersRepository.ts | 1 + .../http/controllers/ListUserController.ts | 15 +++++++++++++++ .../users/infra/http/routes/users.routes.ts | 4 ++++ .../typeorm/repositories/UsersRepository.ts | 6 ++++++ src/modules/users/services/ListUserService.ts | 19 +++++++++++++++++++ 5 files changed, 45 insertions(+) create mode 100644 src/modules/users/infra/http/controllers/ListUserController.ts create mode 100644 src/modules/users/services/ListUserService.ts diff --git a/src/modules/users/domain/repositories/IUsersRepository.ts b/src/modules/users/domain/repositories/IUsersRepository.ts index 6e2bcac..19baaf8 100644 --- a/src/modules/users/domain/repositories/IUsersRepository.ts +++ b/src/modules/users/domain/repositories/IUsersRepository.ts @@ -2,6 +2,7 @@ import { ICreateUserDTO } from '../dtos/ICreateUserDTO'; import { IUser } from '../models/IUser'; interface IUsersRepository { + findAll(): Promise; create(data: ICreateUserDTO): Promise; findByEmail(email: string): Promise; findById(id: string): Promise; diff --git a/src/modules/users/infra/http/controllers/ListUserController.ts b/src/modules/users/infra/http/controllers/ListUserController.ts new file mode 100644 index 0000000..3096062 --- /dev/null +++ b/src/modules/users/infra/http/controllers/ListUserController.ts @@ -0,0 +1,15 @@ +import { ListUserService } from '@modules/users/services/ListUserService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class ListUserController { + async handle(request: Request, response: Response): Promise { + const listUsers = container.resolve(ListUserService); + + const users = await listUsers.execute(); + + return response.json(users); + } +} + +export { ListUserController }; diff --git a/src/modules/users/infra/http/routes/users.routes.ts b/src/modules/users/infra/http/routes/users.routes.ts index 64c89dd..458f654 100644 --- a/src/modules/users/infra/http/routes/users.routes.ts +++ b/src/modules/users/infra/http/routes/users.routes.ts @@ -1,10 +1,12 @@ import { celebrate, Segments, Joi } from 'celebrate'; import { Router } from 'express'; import { CreateUserController } from '../controllers/CreateUserController'; +import { ListUserController } from '../controllers/ListUserController'; const usersRoutes = Router(); const createUserController = new CreateUserController(); +const listUserController = new ListUserController(); usersRoutes.post( '/', @@ -18,4 +20,6 @@ usersRoutes.post( createUserController.handle, ); +usersRoutes.get('/', listUserController.handle); + export { usersRoutes }; diff --git a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts index 20aa96d..da4041e 100644 --- a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts +++ b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts @@ -11,6 +11,12 @@ class UsersRepository implements IUsersRepository { this.repository = getRepository(User); } + findAll(): Promise { + const users = this.repository.find(); + + return users; + } + async create({ name, email, password }: ICreateUserDTO): Promise { const createUser = this.repository.create({ name, diff --git a/src/modules/users/services/ListUserService.ts b/src/modules/users/services/ListUserService.ts new file mode 100644 index 0000000..6a3ab52 --- /dev/null +++ b/src/modules/users/services/ListUserService.ts @@ -0,0 +1,19 @@ +import { inject, injectable } from 'tsyringe'; +import { IUser } from '../domain/models/IUser'; +import { IUsersRepository } from '../domain/repositories/IUsersRepository'; + +@injectable() +class ListUserService { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + ) {} + + async execute(): Promise { + const users = await this.usersRepository.findAll(); + + return users; + } +} + +export { ListUserService }; From dd53b5be4509e173627ae167683129a275f90eda Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 17:47:44 -0300 Subject: [PATCH 22/92] chore: enabling typeroots --- tsconfig.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 4aaf597..f5ca205 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -34,7 +34,10 @@ "@shared/*": ["src/shared/*"] }, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + "typeRoots": [ + "@types", + "./node_modules/@types" + ], /* Specify multiple folders that act like `./node_modules/@types`. */ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ "resolveJsonModule": true, /* Enable importing .json files */ From e6a4ab04179350d9389c1bd54e03a454599becd1 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 19:28:25 -0300 Subject: [PATCH 23/92] feat: admin user creation --- src/shared/infra/typeorm/index.ts | 15 +++++++++++++-- src/shared/infra/typeorm/seed/admin.ts | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/shared/infra/typeorm/seed/admin.ts diff --git a/src/shared/infra/typeorm/index.ts b/src/shared/infra/typeorm/index.ts index c6e6a48..60790a5 100644 --- a/src/shared/infra/typeorm/index.ts +++ b/src/shared/infra/typeorm/index.ts @@ -1,3 +1,14 @@ -import { createConnection } from 'typeorm'; +import { Connection, createConnection, getConnectionOptions } from 'typeorm'; -createConnection(); +export default async (): Promise => { + const defaultOptions = await getConnectionOptions(); + + return createConnection( + Object.assign(defaultOptions, { + database: + process.env.NODE_ENV === 'test' + ? 'lost-and-found_test' + : defaultOptions.database, + }), + ); +}; diff --git a/src/shared/infra/typeorm/seed/admin.ts b/src/shared/infra/typeorm/seed/admin.ts new file mode 100644 index 0000000..43112d2 --- /dev/null +++ b/src/shared/infra/typeorm/seed/admin.ts @@ -0,0 +1,21 @@ +import { hash } from 'bcrypt'; +import { v4 as uuidV4 } from 'uuid'; + +import createConnection from '../index'; + +async function create() { + const connection = await createConnection(); + + const id = uuidV4(); + const password = await hash('admin', 8); + + await connection.query( + `INSERT INTO USERS(id, name, email, password, "isAdmin", created_at, updated_at) + values('${id}', 'admin', 'admin@admin.com.br', '${password}', true, 'now()', 'now()') + `, + ); + + await connection.close(); +} + +create().then(() => console.log('User admin created.')); From 6dcee787eb42c628057644afb1af4f5ce90d858e Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 20:01:49 -0300 Subject: [PATCH 24/92] refactor: admin route --- .../users/infra/http/routes/admin.routes.ts | 19 +++++++++++++++++++ .../users/infra/http/routes/users.routes.ts | 4 ---- src/shared/infra/http/routes/index.ts | 2 ++ src/shared/infra/typeorm/seed/admin.ts | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 src/modules/users/infra/http/routes/admin.routes.ts diff --git a/src/modules/users/infra/http/routes/admin.routes.ts b/src/modules/users/infra/http/routes/admin.routes.ts new file mode 100644 index 0000000..025ce12 --- /dev/null +++ b/src/modules/users/infra/http/routes/admin.routes.ts @@ -0,0 +1,19 @@ +import ensureAdmin from '@shared/infra/http/middlewares/ensureAdmin'; +import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; + +import { Router } from 'express'; + +import { ListUserController } from '../controllers/ListUserController'; + +const adminRoutes = Router(); + +const listUserController = new ListUserController(); + +adminRoutes.get( + '/', + ensureAuthenticated, + ensureAdmin, + listUserController.handle, +); + +export { adminRoutes }; diff --git a/src/modules/users/infra/http/routes/users.routes.ts b/src/modules/users/infra/http/routes/users.routes.ts index 458f654..64c89dd 100644 --- a/src/modules/users/infra/http/routes/users.routes.ts +++ b/src/modules/users/infra/http/routes/users.routes.ts @@ -1,12 +1,10 @@ import { celebrate, Segments, Joi } from 'celebrate'; import { Router } from 'express'; import { CreateUserController } from '../controllers/CreateUserController'; -import { ListUserController } from '../controllers/ListUserController'; const usersRoutes = Router(); const createUserController = new CreateUserController(); -const listUserController = new ListUserController(); usersRoutes.post( '/', @@ -20,6 +18,4 @@ usersRoutes.post( createUserController.handle, ); -usersRoutes.get('/', listUserController.handle); - export { usersRoutes }; diff --git a/src/shared/infra/http/routes/index.ts b/src/shared/infra/http/routes/index.ts index cb8cb75..5fd2a3e 100644 --- a/src/shared/infra/http/routes/index.ts +++ b/src/shared/infra/http/routes/index.ts @@ -1,3 +1,4 @@ +import { adminRoutes } from '@modules/users/infra/http/routes/admin.routes'; import { sessionsRoutes } from '@modules/users/infra/http/routes/sessions.routes'; import { usersRoutes } from '@modules/users/infra/http/routes/users.routes'; import { Router } from 'express'; @@ -6,5 +7,6 @@ const routes = Router(); routes.use('/users', usersRoutes); routes.use('/sessions', sessionsRoutes); +routes.use('/admin', adminRoutes); export { routes }; diff --git a/src/shared/infra/typeorm/seed/admin.ts b/src/shared/infra/typeorm/seed/admin.ts index 43112d2..561e17c 100644 --- a/src/shared/infra/typeorm/seed/admin.ts +++ b/src/shared/infra/typeorm/seed/admin.ts @@ -7,7 +7,7 @@ async function create() { const connection = await createConnection(); const id = uuidV4(); - const password = await hash('admin', 8); + const password = await hash('123456', 8); await connection.query( `INSERT INTO USERS(id, name, email, password, "isAdmin", created_at, updated_at) From a323ad2b2eda96fe2d1a0ceddf1b666ae51f89a5 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 20:02:43 -0300 Subject: [PATCH 25/92] feat: middleware ensure admin --- src/modules/users/domain/models/IUser.ts | 1 + .../infra/http/middlewares/ensureAdmin.ts | 20 +++++++++++++++++++ src/shared/infra/http/server.ts | 4 +++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/shared/infra/http/middlewares/ensureAdmin.ts diff --git a/src/modules/users/domain/models/IUser.ts b/src/modules/users/domain/models/IUser.ts index 581a404..ab13261 100644 --- a/src/modules/users/domain/models/IUser.ts +++ b/src/modules/users/domain/models/IUser.ts @@ -4,6 +4,7 @@ interface IUser { email: string; password: string; avatar: string; + isAdmin: boolean; created_at: Date; updated_at: Date; } diff --git a/src/shared/infra/http/middlewares/ensureAdmin.ts b/src/shared/infra/http/middlewares/ensureAdmin.ts new file mode 100644 index 0000000..809d7dc --- /dev/null +++ b/src/shared/infra/http/middlewares/ensureAdmin.ts @@ -0,0 +1,20 @@ +import { UsersRepository } from '@modules/users/infra/typeorm/repositories/UsersRepository'; +import { AppError } from '@shared/errors/AppError'; +import { NextFunction, Request, Response } from 'express'; + +export default async function ensureAdmin( + request: Request, + response: Response, + next: NextFunction, +) { + const { id } = request.user; + + const usersRepository = new UsersRepository(); + const user = await usersRepository.findById(id); + + if (!user.isAdmin) { + throw new AppError("User isn't admin."); + } + + return next(); +} diff --git a/src/shared/infra/http/server.ts b/src/shared/infra/http/server.ts index f3bf2f8..5060b70 100644 --- a/src/shared/infra/http/server.ts +++ b/src/shared/infra/http/server.ts @@ -6,9 +6,11 @@ import { errors } from 'celebrate'; import { routes } from './routes'; import { AppError } from '@shared/errors/AppError'; -import '@shared/infra/typeorm'; +import createConnection from '@shared/infra/typeorm'; + import '@shared/container'; +createConnection(); const app = express(); app.use(cors()); From 8940516ead01f8f39afbd184f31c4c14ba15eecb Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 18 Jan 2022 20:03:03 -0300 Subject: [PATCH 26/92] chore: adding send:admin --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index d9edcfb..5cdce5d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "start": "ts-node-dev -r tsconfig-paths/register --inspect --transpile-only --ignore-watch node_modules src/shared/infra/http/server.ts", "typeorm": "ts-node-dev -r tsconfig-paths/register ./node_modules/typeorm/cli", "lint": "eslint . --ext .ts", - "lint-fix": "eslint . --ext .ts --fix" + "lint-fix": "eslint . --ext .ts --fix", + "seed:admin": "ts-node-dev -r tsconfig-paths/register src/shared/infra/typeorm/seed/admin.ts" }, "devDependencies": { "@types/bcrypt": "^5.0.0", From bcac11695f53ecb2d6e51e2a727f43664e8c0bdb Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 00:06:13 -0300 Subject: [PATCH 27/92] feat: update user profile data --- .../domain/repositories/IUsersRepository.ts | 1 + .../controllers/UpdateProfileController.ts | 25 +++++++ .../users/infra/http/routes/profile.routes.ts | 30 ++++++++ .../typeorm/repositories/UsersRepository.ts | 4 ++ .../users/services/UpdateProfileService.ts | 70 +++++++++++++++++++ src/shared/infra/http/routes/index.ts | 2 + 6 files changed, 132 insertions(+) create mode 100644 src/modules/users/infra/http/controllers/UpdateProfileController.ts create mode 100644 src/modules/users/infra/http/routes/profile.routes.ts create mode 100644 src/modules/users/services/UpdateProfileService.ts diff --git a/src/modules/users/domain/repositories/IUsersRepository.ts b/src/modules/users/domain/repositories/IUsersRepository.ts index 19baaf8..94d4e99 100644 --- a/src/modules/users/domain/repositories/IUsersRepository.ts +++ b/src/modules/users/domain/repositories/IUsersRepository.ts @@ -2,6 +2,7 @@ import { ICreateUserDTO } from '../dtos/ICreateUserDTO'; import { IUser } from '../models/IUser'; interface IUsersRepository { + save(user: IUser): Promise; findAll(): Promise; create(data: ICreateUserDTO): Promise; findByEmail(email: string): Promise; diff --git a/src/modules/users/infra/http/controllers/UpdateProfileController.ts b/src/modules/users/infra/http/controllers/UpdateProfileController.ts new file mode 100644 index 0000000..8ae28fd --- /dev/null +++ b/src/modules/users/infra/http/controllers/UpdateProfileController.ts @@ -0,0 +1,25 @@ +import { UpdateProfileService } from '@modules/users/services/UpdateProfileService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class UpdateProfileController { + async handle(request: Request, response: Response): Promise { + const user_id = request.user.id; + + const { name, email, password, old_password } = request.body; + + const updateProfileService = container.resolve(UpdateProfileService); + + const updateProfile = await updateProfileService.execute({ + user_id, + name, + email, + password, + old_password, + }); + + return response.json(updateProfile); + } +} + +export { UpdateProfileController }; diff --git a/src/modules/users/infra/http/routes/profile.routes.ts b/src/modules/users/infra/http/routes/profile.routes.ts new file mode 100644 index 0000000..fd9726f --- /dev/null +++ b/src/modules/users/infra/http/routes/profile.routes.ts @@ -0,0 +1,30 @@ +import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; +import { celebrate, Segments, Joi } from 'celebrate'; +import { Router } from 'express'; +import { UpdateProfileController } from '../controllers/UpdateProfileController'; + +const profileRoutes = Router(); + +const updateProfileController = new UpdateProfileController(); + +profileRoutes.put( + '/', + ensureAuthenticated, + celebrate({ + [Segments.BODY]: { + name: Joi.string().required().min(6).max(36), + email: Joi.string().required().email(), + old_password: Joi.string().min(6).max(18), + password: Joi.string().optional().min(6).max(18), + password_confirmation: Joi.string() + .valid(Joi.ref('password')) + .when('password', { + is: Joi.exist(), + then: Joi.required(), + }), + }, + }), + updateProfileController.handle, +); + +export { profileRoutes }; diff --git a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts index da4041e..6e930f3 100644 --- a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts +++ b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts @@ -11,6 +11,10 @@ class UsersRepository implements IUsersRepository { this.repository = getRepository(User); } + async save(user: IUser): Promise { + await this.repository.save(user); + } + findAll(): Promise { const users = this.repository.find(); diff --git a/src/modules/users/services/UpdateProfileService.ts b/src/modules/users/services/UpdateProfileService.ts new file mode 100644 index 0000000..4be0a1e --- /dev/null +++ b/src/modules/users/services/UpdateProfileService.ts @@ -0,0 +1,70 @@ +import { AppError } from '@shared/errors/AppError'; + +import { inject, injectable } from 'tsyringe'; +import { IUser } from '../domain/models/IUser'; +import { IUsersRepository } from '../domain/repositories/IUsersRepository'; +import { IHashProvider } from '../providers/models/IHashProvider'; + +interface IRequest { + user_id: string; + name: string; + email: string; + password: string; + old_password: string; +} + +@injectable() +class UpdateProfileService { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + @inject('HashProvider') + private hashProvider: IHashProvider, + ) {} + + async execute({ + user_id, + name, + email, + password, + old_password, + }: IRequest): Promise { + const user = await this.usersRepository.findById(user_id); + + if (!user) { + throw new AppError('User not found.'); + } + + const userEmail = await this.usersRepository.findByEmail(email); + + if (userEmail && userEmail.id !== user_id) { + throw new AppError('There is already one user with this email.'); + } + + if (password && !old_password) { + throw new AppError('Old password is required.'); + } + + if (password && old_password) { + const checkOldPassword = await this.hashProvider.compareHash( + old_password, + user.password, + ); + + if (!checkOldPassword) { + throw new AppError('Old password does not match.'); + } + + user.password = await this.hashProvider.generateHash(password); + } + + user.name = name; + user.email = email; + + await this.usersRepository.save(user); + + return user; + } +} + +export { UpdateProfileService }; diff --git a/src/shared/infra/http/routes/index.ts b/src/shared/infra/http/routes/index.ts index 5fd2a3e..8f3bf37 100644 --- a/src/shared/infra/http/routes/index.ts +++ b/src/shared/infra/http/routes/index.ts @@ -1,4 +1,5 @@ import { adminRoutes } from '@modules/users/infra/http/routes/admin.routes'; +import { profileRoutes } from '@modules/users/infra/http/routes/profile.routes'; import { sessionsRoutes } from '@modules/users/infra/http/routes/sessions.routes'; import { usersRoutes } from '@modules/users/infra/http/routes/users.routes'; import { Router } from 'express'; @@ -8,5 +9,6 @@ const routes = Router(); routes.use('/users', usersRoutes); routes.use('/sessions', sessionsRoutes); routes.use('/admin', adminRoutes); +routes.use('/profile', profileRoutes); export { routes }; From 72c22804c24cacbc38142b990dfc3ca6603b056e Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 00:28:57 -0300 Subject: [PATCH 28/92] feat: delete user --- .../domain/repositories/IUsersRepository.ts | 1 + .../http/controllers/DeleteUserController.ts | 19 +++++++++++++ .../users/infra/http/routes/admin.routes.ts | 9 +++++++ .../typeorm/repositories/UsersRepository.ts | 4 +++ .../users/services/DeleteUserService.ts | 27 +++++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 src/modules/users/infra/http/controllers/DeleteUserController.ts create mode 100644 src/modules/users/services/DeleteUserService.ts diff --git a/src/modules/users/domain/repositories/IUsersRepository.ts b/src/modules/users/domain/repositories/IUsersRepository.ts index 94d4e99..0bb589d 100644 --- a/src/modules/users/domain/repositories/IUsersRepository.ts +++ b/src/modules/users/domain/repositories/IUsersRepository.ts @@ -2,6 +2,7 @@ import { ICreateUserDTO } from '../dtos/ICreateUserDTO'; import { IUser } from '../models/IUser'; interface IUsersRepository { + findByDelete(id: string): Promise; save(user: IUser): Promise; findAll(): Promise; create(data: ICreateUserDTO): Promise; diff --git a/src/modules/users/infra/http/controllers/DeleteUserController.ts b/src/modules/users/infra/http/controllers/DeleteUserController.ts new file mode 100644 index 0000000..94d81c4 --- /dev/null +++ b/src/modules/users/infra/http/controllers/DeleteUserController.ts @@ -0,0 +1,19 @@ +import { DeleteUserService } from '@modules/users/services/DeleteUserService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class DeleteUserController { + async handle(request: Request, response: Response): Promise { + const { id } = request.params; + + const deleteUserService = container.resolve(DeleteUserService); + + await deleteUserService.execute({ + id, + }); + + return response.status(204).json(); + } +} + +export { DeleteUserController }; diff --git a/src/modules/users/infra/http/routes/admin.routes.ts b/src/modules/users/infra/http/routes/admin.routes.ts index 025ce12..08c0479 100644 --- a/src/modules/users/infra/http/routes/admin.routes.ts +++ b/src/modules/users/infra/http/routes/admin.routes.ts @@ -2,12 +2,14 @@ import ensureAdmin from '@shared/infra/http/middlewares/ensureAdmin'; import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; import { Router } from 'express'; +import { DeleteUserController } from '../controllers/DeleteUserController'; import { ListUserController } from '../controllers/ListUserController'; const adminRoutes = Router(); const listUserController = new ListUserController(); +const deleteUserController = new DeleteUserController(); adminRoutes.get( '/', @@ -16,4 +18,11 @@ adminRoutes.get( listUserController.handle, ); +adminRoutes.delete( + '/:id', + ensureAuthenticated, + ensureAdmin, + deleteUserController.handle, +); + export { adminRoutes }; diff --git a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts index 6e930f3..99d2934 100644 --- a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts +++ b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts @@ -11,6 +11,10 @@ class UsersRepository implements IUsersRepository { this.repository = getRepository(User); } + async findByDelete(id: string): Promise { + await this.repository.delete(id); + } + async save(user: IUser): Promise { await this.repository.save(user); } diff --git a/src/modules/users/services/DeleteUserService.ts b/src/modules/users/services/DeleteUserService.ts new file mode 100644 index 0000000..f4ca825 --- /dev/null +++ b/src/modules/users/services/DeleteUserService.ts @@ -0,0 +1,27 @@ +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { IUsersRepository } from '../domain/repositories/IUsersRepository'; + +interface IRequest { + id: string; +} + +@injectable() +class DeleteUserService { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + ) {} + + async execute({ id }: IRequest): Promise { + const user = await this.usersRepository.findById(id); + + if (!user) { + throw new AppError('User not found.'); + } + + await this.usersRepository.findByDelete(id); + } +} + +export { DeleteUserService }; From b2f046207bd3b440e6fef1780636ccdc4a78913b Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 00:43:29 -0300 Subject: [PATCH 29/92] refactor: applying the class transformer to the controllers --- package.json | 1 + .../users/infra/http/controllers/CreateUserController.ts | 3 ++- src/modules/users/infra/typeorm/entities/User.ts | 3 +++ src/modules/users/services/DeleteUserService.ts | 2 +- src/modules/users/services/UpdateProfileService.ts | 4 ++-- yarn.lock | 5 +++++ 6 files changed, 14 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 5cdce5d..77586c7 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "dependencies": { "bcrypt": "^5.0.1", "celebrate": "^15.0.0", + "class-transformer": "^0.5.1", "cors": "^2.8.5", "express": "^4.17.2", "express-async-errors": "^3.1.1", diff --git a/src/modules/users/infra/http/controllers/CreateUserController.ts b/src/modules/users/infra/http/controllers/CreateUserController.ts index 84ae056..bf6d791 100644 --- a/src/modules/users/infra/http/controllers/CreateUserController.ts +++ b/src/modules/users/infra/http/controllers/CreateUserController.ts @@ -1,5 +1,6 @@ import { CreateUserService } from '@modules/users/services/CreateUserService'; import { Request, Response } from 'express'; +import { instanceToInstance } from 'class-transformer'; import { container } from 'tsyringe'; class CreateUserController { @@ -14,7 +15,7 @@ class CreateUserController { password, }); - return response.status(201).json(createUser); + return response.status(201).json(instanceToInstance(createUser)); } } diff --git a/src/modules/users/infra/typeorm/entities/User.ts b/src/modules/users/infra/typeorm/entities/User.ts index ce8aa55..e342a24 100644 --- a/src/modules/users/infra/typeorm/entities/User.ts +++ b/src/modules/users/infra/typeorm/entities/User.ts @@ -6,6 +6,8 @@ import { PrimaryColumn, UpdateDateColumn, } from 'typeorm'; +import { Exclude } from 'class-transformer'; + import { v4 as uuidV4 } from 'uuid'; @Entity('users') @@ -20,6 +22,7 @@ class User implements IUser { email: string; @Column() + @Exclude() password: string; @Column() diff --git a/src/modules/users/services/DeleteUserService.ts b/src/modules/users/services/DeleteUserService.ts index f4ca825..f09b75a 100644 --- a/src/modules/users/services/DeleteUserService.ts +++ b/src/modules/users/services/DeleteUserService.ts @@ -17,7 +17,7 @@ class DeleteUserService { const user = await this.usersRepository.findById(id); if (!user) { - throw new AppError('User not found.'); + throw new AppError('User not found.', 404); } await this.usersRepository.findByDelete(id); diff --git a/src/modules/users/services/UpdateProfileService.ts b/src/modules/users/services/UpdateProfileService.ts index 4be0a1e..07825e4 100644 --- a/src/modules/users/services/UpdateProfileService.ts +++ b/src/modules/users/services/UpdateProfileService.ts @@ -32,7 +32,7 @@ class UpdateProfileService { const user = await this.usersRepository.findById(user_id); if (!user) { - throw new AppError('User not found.'); + throw new AppError('User not found.', 404); } const userEmail = await this.usersRepository.findByEmail(email); @@ -52,7 +52,7 @@ class UpdateProfileService { ); if (!checkOldPassword) { - throw new AppError('Old password does not match.'); + throw new AppError('Old password does not match.', 401); } user.password = await this.hashProvider.generateHash(password); diff --git a/yarn.lock b/yarn.lock index e8c426f..536712d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -526,6 +526,11 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== +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== + cli-highlight@^2.1.11: version "2.1.11" resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" From d79f0cc2e853cf06459d6f24c2c428bb57a94623 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 00:52:20 -0300 Subject: [PATCH 30/92] chore: adding dotenv --- .env.example | 2 ++ package.json | 1 + src/shared/infra/http/server.ts | 3 ++- yarn.lock | 5 +++++ 4 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..39ace0d --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +PORT = 3333 +APP_SECRET = 91cf4aa79dbb713fbf551ce3efa9c12d diff --git a/package.json b/package.json index 77586c7..a091ae9 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "celebrate": "^15.0.0", "class-transformer": "^0.5.1", "cors": "^2.8.5", + "dotenv": "^14.2.0", "express": "^4.17.2", "express-async-errors": "^3.1.1", "jsonwebtoken": "^8.5.1", diff --git a/src/shared/infra/http/server.ts b/src/shared/infra/http/server.ts index 5060b70..574c7a2 100644 --- a/src/shared/infra/http/server.ts +++ b/src/shared/infra/http/server.ts @@ -1,4 +1,5 @@ import 'reflect-metadata'; +import 'dotenv/config'; import express, { NextFunction, Request, Response } from 'express'; import 'express-async-errors'; import cors from 'cors'; @@ -37,5 +38,5 @@ app.use( ); app.listen(3333, () => { - console.log('Server started on port 3333'); + console.log(`Server started on port ${process.env.PORT}`); }); diff --git a/yarn.lock b/yarn.lock index 536712d..e40002b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -681,6 +681,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dotenv@^14.2.0: + version "14.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.2.0.tgz#7e77fd5dd6cff5942c4496e1acf2d0f37a9e67aa" + integrity sha512-05POuPJyPpO6jqzTNweQFfAyMSD4qa4lvsMOWyTRTdpHKy6nnnN+IYWaXF+lHivhBH/ufDKlR4IWCAN3oPnHuw== + dotenv@^8.2.0: version "8.6.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" From d11a637f95593f7f51c0664120dc0de96ecc58ed Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 01:49:15 -0300 Subject: [PATCH 31/92] feat: upload configuration --- src/config/upload.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/config/upload.ts diff --git a/src/config/upload.ts b/src/config/upload.ts new file mode 100644 index 0000000..359e7bb --- /dev/null +++ b/src/config/upload.ts @@ -0,0 +1,19 @@ +import path from 'path'; +import multer from 'multer'; +import crypto from 'crypto'; + +const uploadFolder = path.resolve(__dirname, '..', '..', 'uploads'); + +export default { + directory: uploadFolder, + storage: multer.diskStorage({ + destination: uploadFolder, + filename(request, file, callback) { + const fileHash = crypto.randomBytes(10).toString('hex'); + + const fileName = `${fileHash}-${file.originalname}`; + + callback(null, fileName); + }, + }), +}; From 11752a40fdc8642e7df16ee4f228e22b0068899b Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 01:49:44 -0300 Subject: [PATCH 32/92] chore: adding multer --- package.json | 2 + .../controllers/UpdateProfileController.ts | 3 +- yarn.lock | 139 +++++++++++++++++- 3 files changed, 138 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index a091ae9..37f260a 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@types/express": "^4.17.13", "@types/joi": "^17.2.3", "@types/jsonwebtoken": "^8.5.8", + "@types/multer": "^1.4.7", "@types/node": "^17.0.8", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.10.0", @@ -37,6 +38,7 @@ "express": "^4.17.2", "express-async-errors": "^3.1.1", "jsonwebtoken": "^8.5.1", + "multer": "^1.4.4", "pg": "^8.7.1", "reflect-metadata": "^0.1.13", "tsyringe": "^4.6.0", diff --git a/src/modules/users/infra/http/controllers/UpdateProfileController.ts b/src/modules/users/infra/http/controllers/UpdateProfileController.ts index 8ae28fd..fbc32b7 100644 --- a/src/modules/users/infra/http/controllers/UpdateProfileController.ts +++ b/src/modules/users/infra/http/controllers/UpdateProfileController.ts @@ -1,5 +1,6 @@ import { UpdateProfileService } from '@modules/users/services/UpdateProfileService'; import { Request, Response } from 'express'; +import { instanceToInstance } from 'class-transformer'; import { container } from 'tsyringe'; class UpdateProfileController { @@ -18,7 +19,7 @@ class UpdateProfileController { old_password, }); - return response.json(updateProfile); + return response.json(instanceToInstance(updateProfile)); } } diff --git a/yarn.lock b/yarn.lock index e40002b..13ba2f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -137,7 +137,7 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/express@^4.17.13": +"@types/express@*", "@types/express@^4.17.13": version "4.17.13" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== @@ -176,6 +176,13 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== +"@types/multer@^1.4.7": + version "1.4.7" + resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.7.tgz#89cf03547c28c7bbcc726f029e2a76a7232cc79e" + integrity sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA== + dependencies: + "@types/express" "*" + "@types/node@*", "@types/node@^17.0.8": version "17.0.8" resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b" @@ -369,6 +376,11 @@ app-root-path@^3.0.0: resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== +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 || ^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" @@ -479,6 +491,14 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +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.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" @@ -574,6 +594,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.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" + console-control-strings@^1.0.0, console-control-strings@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" @@ -601,6 +631,11 @@ cookie@0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== +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" @@ -662,6 +697,14 @@ detect-libc@^1.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +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@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -1181,7 +1224,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, 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== @@ -1227,6 +1270,16 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -1444,6 +1497,13 @@ minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" +mkdirp@^0.5.4: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + mkdirp@^1.0.3, mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" @@ -1464,6 +1524,20 @@ ms@2.1.3, 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.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.4.tgz#e2bc6cac0df57a8832b858d7418ccaa8ebaf7d8c" + integrity sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw== + dependencies: + append-field "^1.0.0" + busboy "^0.2.11" + concat-stream "^1.5.2" + mkdirp "^0.5.4" + object-assign "^4.1.1" + on-finished "^2.3.0" + type-is "^1.6.4" + xtend "^4.0.0" + mz@^2.4.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" @@ -1522,7 +1596,7 @@ object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -on-finished@~2.3.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= @@ -1702,6 +1776,11 @@ prettier@^2.5.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== +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== + proxy-addr@~2.0.7: version "2.0.7" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" @@ -1740,6 +1819,29 @@ raw-body@2.4.2: iconv-lite "0.4.24" unpipe "1.0.0" +readable-stream@1.1.x: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.2.2: + 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== + 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.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" @@ -1816,6 +1918,11 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: 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== + "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -1935,6 +2042,11 @@ split2@^4.1.0: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +streamsearch@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" + integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= + "string-width@^1.0.2 || 2 || 3 || 4", 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" @@ -1951,6 +2063,18 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +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@^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" @@ -2122,7 +2246,7 @@ type-fest@^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-is@~1.6.18: +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== @@ -2130,6 +2254,11 @@ type-is@~1.6.18: 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 sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + typeorm@^0.2.41: version "0.2.41" resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.41.tgz#88758101ac158dc0a0a903d70eaacea2974281cc" @@ -2169,7 +2298,7 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@^1.0.1: +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 sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= From 10cf991387a390b7644ebb9568cfc37d0c90ffe2 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 13:25:00 -0300 Subject: [PATCH 33/92] feat: avatar upload --- .../controllers/UpdateAvatarUserController.ts | 19 ++++++++ .../users/infra/http/routes/users.routes.ts | 14 ++++++ .../users/services/UpdateAvatarUserService.ts | 46 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/modules/users/infra/http/controllers/UpdateAvatarUserController.ts create mode 100644 src/modules/users/services/UpdateAvatarUserService.ts diff --git a/src/modules/users/infra/http/controllers/UpdateAvatarUserController.ts b/src/modules/users/infra/http/controllers/UpdateAvatarUserController.ts new file mode 100644 index 0000000..c8dfa9c --- /dev/null +++ b/src/modules/users/infra/http/controllers/UpdateAvatarUserController.ts @@ -0,0 +1,19 @@ +import { Request, Response } from 'express'; +import { instanceToInstance } from 'class-transformer'; +import { container } from 'tsyringe'; +import { UpdateAvatarUserService } from '@modules/users/services/UpdateAvatarUserService'; + +class UpdateAvatarUserController { + async handle(request: Request, response: Response): Promise { + const updateAvatarUserService = container.resolve(UpdateAvatarUserService); + + const updateAvatar = await updateAvatarUserService.execute({ + user_id: request.user.id, + avatarFileName: request.file?.filename, + }); + + return response.json(instanceToInstance(updateAvatar)); + } +} + +export { UpdateAvatarUserController }; diff --git a/src/modules/users/infra/http/routes/users.routes.ts b/src/modules/users/infra/http/routes/users.routes.ts index 64c89dd..0b7a0eb 100644 --- a/src/modules/users/infra/http/routes/users.routes.ts +++ b/src/modules/users/infra/http/routes/users.routes.ts @@ -1,10 +1,17 @@ import { celebrate, Segments, Joi } from 'celebrate'; import { Router } from 'express'; import { CreateUserController } from '../controllers/CreateUserController'; +import uploadConfig from '@config/upload'; +import multer from 'multer'; +import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; +import { UpdateAvatarUserController } from '../controllers/UpdateAvatarUserController'; const usersRoutes = Router(); const createUserController = new CreateUserController(); +const updateAvatarUserController = new UpdateAvatarUserController(); + +const upload = multer(uploadConfig); usersRoutes.post( '/', @@ -18,4 +25,11 @@ usersRoutes.post( createUserController.handle, ); +usersRoutes.patch( + '/avatar', + ensureAuthenticated, + upload.single('avatar'), + updateAvatarUserController.handle, +); + export { usersRoutes }; diff --git a/src/modules/users/services/UpdateAvatarUserService.ts b/src/modules/users/services/UpdateAvatarUserService.ts new file mode 100644 index 0000000..c948548 --- /dev/null +++ b/src/modules/users/services/UpdateAvatarUserService.ts @@ -0,0 +1,46 @@ +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { IUser } from '../domain/models/IUser'; +import { IUsersRepository } from '../domain/repositories/IUsersRepository'; +import fs from 'fs'; +import path from 'path'; +import uploadConfig from '@config/upload'; + +interface IResquest { + user_id: string; + avatarFileName: string; +} + +@injectable() +class UpdateAvatarUserService { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + ) {} + + async execute({ user_id, avatarFileName }: IResquest): Promise { + const user = await this.usersRepository.findById(user_id); + + if (!user) { + throw new AppError('User not found', 404); + } + + if (user.avatar) { + const userAvatarFilePath = path.join(uploadConfig.directory, user.avatar); + + const userAvatarFileExists = await fs.promises.stat(userAvatarFilePath); + + if (userAvatarFileExists) { + await fs.promises.unlink(userAvatarFilePath); + } + } + + user.avatar = avatarFileName; + + await this.usersRepository.save(user); + + return user; + } +} + +export { UpdateAvatarUserService }; From 74a0db9aae09e9835a78f4403c08d1009a5371e2 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 13:39:23 -0300 Subject: [PATCH 34/92] chore: adding routes static --- src/shared/infra/http/server.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shared/infra/http/server.ts b/src/shared/infra/http/server.ts index 574c7a2..8521ab5 100644 --- a/src/shared/infra/http/server.ts +++ b/src/shared/infra/http/server.ts @@ -6,6 +6,7 @@ import cors from 'cors'; import { errors } from 'celebrate'; import { routes } from './routes'; import { AppError } from '@shared/errors/AppError'; +import uploadConfig from '@config/upload'; import createConnection from '@shared/infra/typeorm'; @@ -16,6 +17,9 @@ const app = express(); app.use(cors()); app.use(express.json()); + +app.use('/file', express.static(uploadConfig.directory)); + app.use(routes); app.use(errors()); From 7d6e7153da8cb830ae39adb998422eb0b81c6809 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 17:26:49 -0300 Subject: [PATCH 35/92] chore: adding migration user tokens --- .../1642610997984-CreateUsersTokens.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/shared/infra/typeorm/migrations/1642610997984-CreateUsersTokens.ts diff --git a/src/shared/infra/typeorm/migrations/1642610997984-CreateUsersTokens.ts b/src/shared/infra/typeorm/migrations/1642610997984-CreateUsersTokens.ts new file mode 100644 index 0000000..20a6e5e --- /dev/null +++ b/src/shared/infra/typeorm/migrations/1642610997984-CreateUsersTokens.ts @@ -0,0 +1,50 @@ +import { MigrationInterface, QueryRunner, Table } from 'typeorm'; + +export class CreateUsersTokens1642610997984 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: 'users_tokens', + columns: [ + { + name: 'id', + type: 'uuid', + isPrimary: true, + }, + { + name: 'token', + type: 'uuid', + }, + { + name: 'user_id', + type: 'uuid', + }, + { + name: 'created_at', + type: 'timestamp', + default: 'now()', + }, + { + name: 'updated_at', + type: 'timestamp', + default: 'now()', + }, + ], + foreignKeys: [ + { + name: 'FKUserToken', + referencedTableName: 'users', + referencedColumnNames: ['id'], + columnNames: ['user_id'], + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }, + ], + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable('users_tokens'); + } +} From 0af3e052e059fe5c166a3c40f3ad3f0d45f4f9e3 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 17:28:43 -0300 Subject: [PATCH 36/92] feat: entities and repositories user token --- src/modules/users/domain/models/IUserToken.ts | 9 +++++ .../repositories/IUsersTokensRepository.ts | 8 ++++ .../users/infra/typeorm/entities/UserToken.ts | 38 +++++++++++++++++++ .../repositories/UserTokensRepository.ts | 28 ++++++++++++++ src/shared/container/index.ts | 7 ++++ 5 files changed, 90 insertions(+) create mode 100644 src/modules/users/domain/models/IUserToken.ts create mode 100644 src/modules/users/domain/repositories/IUsersTokensRepository.ts create mode 100644 src/modules/users/infra/typeorm/entities/UserToken.ts create mode 100644 src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts diff --git a/src/modules/users/domain/models/IUserToken.ts b/src/modules/users/domain/models/IUserToken.ts new file mode 100644 index 0000000..d33e9cb --- /dev/null +++ b/src/modules/users/domain/models/IUserToken.ts @@ -0,0 +1,9 @@ +interface IUserToken { + id: string; + token: string; + user_id: string; + created_at: Date; + updated_at: Date; +} + +export { IUserToken }; diff --git a/src/modules/users/domain/repositories/IUsersTokensRepository.ts b/src/modules/users/domain/repositories/IUsersTokensRepository.ts new file mode 100644 index 0000000..aa4576b --- /dev/null +++ b/src/modules/users/domain/repositories/IUsersTokensRepository.ts @@ -0,0 +1,8 @@ +import { IUserToken } from '../models/IUserToken'; + +interface IUsersTokensRepository { + findByToken(token: string): Promise; + generateToken(user_id: string): Promise; +} + +export { IUsersTokensRepository }; diff --git a/src/modules/users/infra/typeorm/entities/UserToken.ts b/src/modules/users/infra/typeorm/entities/UserToken.ts new file mode 100644 index 0000000..3562be8 --- /dev/null +++ b/src/modules/users/infra/typeorm/entities/UserToken.ts @@ -0,0 +1,38 @@ +import { IUserToken } from '@modules/users/domain/models/IUserToken'; +import { + Column, + CreateDateColumn, + Entity, + Generated, + PrimaryColumn, + UpdateDateColumn, +} from 'typeorm'; + +import { v4 as uuidV4 } from 'uuid'; + +@Entity('users_tokens') +class UserToken implements IUserToken { + @PrimaryColumn() + id: string; + + @Column() + @Generated('uuid') + token: string; + + @Column() + user_id: string; + + @CreateDateColumn() + created_at: Date; + + @UpdateDateColumn() + updated_at: Date; + + constructor() { + if (!this.id) { + this.id = uuidV4(); + } + } +} + +export { UserToken }; diff --git a/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts b/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts new file mode 100644 index 0000000..04a83e1 --- /dev/null +++ b/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts @@ -0,0 +1,28 @@ +import { IUserToken } from '@modules/users/domain/models/IUserToken'; +import { IUsersTokensRepository } from '@modules/users/domain/repositories/IUsersTokensRepository'; +import { getRepository, Repository } from 'typeorm'; +import { UserToken } from '../entities/UserToken'; + +class UserTokensRepository implements IUsersTokensRepository { + private repository: Repository; + + constructor() { + this.repository = getRepository(UserToken); + } + + async findByToken(token: string): Promise { + const userToken = await this.repository.findOne({ token }); + + return userToken; + } + + async generateToken(user_id: string): Promise { + const userToken = this.repository.create({ user_id }); + + await this.repository.save(userToken); + + return userToken; + } +} + +export { UserTokensRepository }; diff --git a/src/shared/container/index.ts b/src/shared/container/index.ts index 8a462b2..1ff67b6 100644 --- a/src/shared/container/index.ts +++ b/src/shared/container/index.ts @@ -3,8 +3,15 @@ import { UsersRepository } from '@modules/users/infra/typeorm/repositories/Users import { container } from 'tsyringe'; import '@modules/users/providers'; +import { IUsersTokensRepository } from '@modules/users/domain/repositories/IUsersTokensRepository'; +import { UserTokensRepository } from '@modules/users/infra/typeorm/repositories/UserTokensRepository'; container.registerSingleton( 'UsersRepository', UsersRepository, ); + +container.registerSingleton( + 'UsersTokensRepository', + UserTokensRepository, +); From fcae5e1484b34bda6a5f44e74a51f01a6c392008 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 17:29:25 -0300 Subject: [PATCH 37/92] feat: send forgot password and reset password services --- .../users/services/ResetPasswordService.ts | 51 +++++++++++++++++++ .../SendForgotPasswordEmailService.ts | 38 ++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/modules/users/services/ResetPasswordService.ts create mode 100644 src/modules/users/services/SendForgotPasswordEmailService.ts diff --git a/src/modules/users/services/ResetPasswordService.ts b/src/modules/users/services/ResetPasswordService.ts new file mode 100644 index 0000000..3a968ba --- /dev/null +++ b/src/modules/users/services/ResetPasswordService.ts @@ -0,0 +1,51 @@ +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { IUsersRepository } from '../domain/repositories/IUsersRepository'; +import { IUsersTokensRepository } from '../domain/repositories/IUsersTokensRepository'; + +import { isAfter, addHours } from 'date-fns'; +import { IHashProvider } from '../providers/models/IHashProvider'; + +interface IResqust { + password: string; + token: string; +} + +@injectable() +class ResetPasswordService { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + @inject('UsersTokensRepository') + private usersTokensRepository: IUsersTokensRepository, + @inject('HashProvider') + private hashProvider: IHashProvider, + ) {} + + async execute({ password, token }: IResqust): Promise { + const userToken = await this.usersTokensRepository.findByToken(token); + + if (!userToken) { + throw new AppError('User token does not exists.', 404); + } + + const user = await this.usersRepository.findById(userToken.user_id); + + if (!user) { + throw new AppError('User does not exists.', 404); + } + + const tokenCreatedAt = userToken.created_at; + const compareDate = addHours(tokenCreatedAt, 3); + + if (isAfter(Date.now(), compareDate)) { + throw new AppError('Token expired.', 401); + } + + user.password = await this.hashProvider.generateHash(password); + + await this.usersRepository.save(user); + } +} + +export { ResetPasswordService }; diff --git a/src/modules/users/services/SendForgotPasswordEmailService.ts b/src/modules/users/services/SendForgotPasswordEmailService.ts new file mode 100644 index 0000000..56b53e0 --- /dev/null +++ b/src/modules/users/services/SendForgotPasswordEmailService.ts @@ -0,0 +1,38 @@ +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { IUsersRepository } from '../domain/repositories/IUsersRepository'; +import { IUsersTokensRepository } from '../domain/repositories/IUsersTokensRepository'; +import path from 'path'; + +interface IResqust { + email: string; +} + +@injectable() +class SendForgotPasswordEmailService { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + @inject('UsersTokensRepository') + private usersTokensRepository: IUsersTokensRepository, + ) {} + + async execute({ email }: IResqust): Promise { + const user = await this.usersRepository.findByEmail(email); + + if (!user) { + throw new AppError('User not found.', 404); + } + + const { token } = await this.usersTokensRepository.generateToken(user.id); + + const forgotPasswordTamplete = path.resolve( + __dirname, + '..', + 'views', + 'forgot_password.hbs', + ); + } +} + +export { SendForgotPasswordEmailService }; From 2a1c5d16b847407ecb8b356f9ea81164b5ed3426 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 17:29:51 -0300 Subject: [PATCH 38/92] chore: adding date fns --- package.json | 1 + src/modules/users/views/forgot_password.hbs | 0 yarn.lock | 5 +++++ 3 files changed, 6 insertions(+) create mode 100644 src/modules/users/views/forgot_password.hbs diff --git a/package.json b/package.json index 37f260a..b8a675b 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "celebrate": "^15.0.0", "class-transformer": "^0.5.1", "cors": "^2.8.5", + "date-fns": "^2.28.0", "dotenv": "^14.2.0", "express": "^4.17.2", "express-async-errors": "^3.1.1", diff --git a/src/modules/users/views/forgot_password.hbs b/src/modules/users/views/forgot_password.hbs new file mode 100644 index 0000000..e69de29 diff --git a/yarn.lock b/yarn.lock index 13ba2f6..5e27c44 100644 --- a/yarn.lock +++ b/yarn.lock @@ -658,6 +658,11 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +date-fns@^2.28.0: + version "2.28.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" + integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" From 25d353087f1c20e7214dc076fd139f5236dd2345 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 19:16:28 -0300 Subject: [PATCH 39/92] refactor: changing usertokens class names --- .../repositories/IUsersTokensRepository.ts | 6 +++--- .../users/infra/http/routes/sessions.routes.ts | 2 +- .../users/infra/typeorm/entities/UserToken.ts | 4 ++-- .../typeorm/repositories/UserTokensRepository.ts | 6 +++--- .../users/services/ResetPasswordService.ts | 8 ++++---- .../services/SendForgotPasswordEmailService.ts | 16 +++++----------- src/shared/container/index.ts | 7 ++++--- src/shared/infra/http/routes/index.ts | 4 +++- 8 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/modules/users/domain/repositories/IUsersTokensRepository.ts b/src/modules/users/domain/repositories/IUsersTokensRepository.ts index aa4576b..4ef8dc1 100644 --- a/src/modules/users/domain/repositories/IUsersTokensRepository.ts +++ b/src/modules/users/domain/repositories/IUsersTokensRepository.ts @@ -1,8 +1,8 @@ import { IUserToken } from '../models/IUserToken'; -interface IUsersTokensRepository { +interface IUserTokensRepository { findByToken(token: string): Promise; - generateToken(user_id: string): Promise; + generate(user_id: string): Promise; } -export { IUsersTokensRepository }; +export { IUserTokensRepository }; diff --git a/src/modules/users/infra/http/routes/sessions.routes.ts b/src/modules/users/infra/http/routes/sessions.routes.ts index 6da4713..d7be388 100644 --- a/src/modules/users/infra/http/routes/sessions.routes.ts +++ b/src/modules/users/infra/http/routes/sessions.routes.ts @@ -7,7 +7,7 @@ const sessionsRoutes = Router(); const createSessionController = new CreateSessionController(); sessionsRoutes.post( - '/', + '/sessions', celebrate({ [Segments.BODY]: { email: Joi.string().required().email(), diff --git a/src/modules/users/infra/typeorm/entities/UserToken.ts b/src/modules/users/infra/typeorm/entities/UserToken.ts index 3562be8..13bd04f 100644 --- a/src/modules/users/infra/typeorm/entities/UserToken.ts +++ b/src/modules/users/infra/typeorm/entities/UserToken.ts @@ -10,9 +10,9 @@ import { import { v4 as uuidV4 } from 'uuid'; -@Entity('users_tokens') +@Entity('user_tokens') class UserToken implements IUserToken { - @PrimaryColumn() + @PrimaryColumn('uuid') id: string; @Column() diff --git a/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts b/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts index 04a83e1..b41ee57 100644 --- a/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts +++ b/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts @@ -1,9 +1,9 @@ import { IUserToken } from '@modules/users/domain/models/IUserToken'; -import { IUsersTokensRepository } from '@modules/users/domain/repositories/IUsersTokensRepository'; +import { IUserTokensRepository } from '@modules/users/domain/repositories/IUsersTokensRepository'; import { getRepository, Repository } from 'typeorm'; import { UserToken } from '../entities/UserToken'; -class UserTokensRepository implements IUsersTokensRepository { +class UserTokensRepository implements IUserTokensRepository { private repository: Repository; constructor() { @@ -16,7 +16,7 @@ class UserTokensRepository implements IUsersTokensRepository { return userToken; } - async generateToken(user_id: string): Promise { + async generate(user_id: string): Promise { const userToken = this.repository.create({ user_id }); await this.repository.save(userToken); diff --git a/src/modules/users/services/ResetPasswordService.ts b/src/modules/users/services/ResetPasswordService.ts index 3a968ba..8d5f9d0 100644 --- a/src/modules/users/services/ResetPasswordService.ts +++ b/src/modules/users/services/ResetPasswordService.ts @@ -1,10 +1,10 @@ import { AppError } from '@shared/errors/AppError'; import { inject, injectable } from 'tsyringe'; import { IUsersRepository } from '../domain/repositories/IUsersRepository'; -import { IUsersTokensRepository } from '../domain/repositories/IUsersTokensRepository'; import { isAfter, addHours } from 'date-fns'; import { IHashProvider } from '../providers/models/IHashProvider'; +import { IUserTokensRepository } from '../domain/repositories/IUsersTokensRepository'; interface IResqust { password: string; @@ -16,14 +16,14 @@ class ResetPasswordService { constructor( @inject('UsersRepository') private usersRepository: IUsersRepository, - @inject('UsersTokensRepository') - private usersTokensRepository: IUsersTokensRepository, + @inject('UserTokensRepository') + private userTokensRepository: IUserTokensRepository, @inject('HashProvider') private hashProvider: IHashProvider, ) {} async execute({ password, token }: IResqust): Promise { - const userToken = await this.usersTokensRepository.findByToken(token); + const userToken = await this.userTokensRepository.findByToken(token); if (!userToken) { throw new AppError('User token does not exists.', 404); diff --git a/src/modules/users/services/SendForgotPasswordEmailService.ts b/src/modules/users/services/SendForgotPasswordEmailService.ts index 56b53e0..ee65b90 100644 --- a/src/modules/users/services/SendForgotPasswordEmailService.ts +++ b/src/modules/users/services/SendForgotPasswordEmailService.ts @@ -1,8 +1,7 @@ import { AppError } from '@shared/errors/AppError'; import { inject, injectable } from 'tsyringe'; import { IUsersRepository } from '../domain/repositories/IUsersRepository'; -import { IUsersTokensRepository } from '../domain/repositories/IUsersTokensRepository'; -import path from 'path'; +import { IUserTokensRepository } from '../domain/repositories/IUsersTokensRepository'; interface IResqust { email: string; @@ -13,8 +12,8 @@ class SendForgotPasswordEmailService { constructor( @inject('UsersRepository') private usersRepository: IUsersRepository, - @inject('UsersTokensRepository') - private usersTokensRepository: IUsersTokensRepository, + @inject('UserTokensRepository') + private userTokensRepository: IUserTokensRepository, ) {} async execute({ email }: IResqust): Promise { @@ -24,14 +23,9 @@ class SendForgotPasswordEmailService { throw new AppError('User not found.', 404); } - const { token } = await this.usersTokensRepository.generateToken(user.id); + const token = await this.userTokensRepository.generate(user.id); - const forgotPasswordTamplete = path.resolve( - __dirname, - '..', - 'views', - 'forgot_password.hbs', - ); + console.log(token); } } diff --git a/src/shared/container/index.ts b/src/shared/container/index.ts index 1ff67b6..7327118 100644 --- a/src/shared/container/index.ts +++ b/src/shared/container/index.ts @@ -3,15 +3,16 @@ import { UsersRepository } from '@modules/users/infra/typeorm/repositories/Users import { container } from 'tsyringe'; import '@modules/users/providers'; -import { IUsersTokensRepository } from '@modules/users/domain/repositories/IUsersTokensRepository'; + import { UserTokensRepository } from '@modules/users/infra/typeorm/repositories/UserTokensRepository'; +import { IUserTokensRepository } from '@modules/users/domain/repositories/IUsersTokensRepository'; container.registerSingleton( 'UsersRepository', UsersRepository, ); -container.registerSingleton( - 'UsersTokensRepository', +container.registerSingleton( + 'UserTokensRepository', UserTokensRepository, ); diff --git a/src/shared/infra/http/routes/index.ts b/src/shared/infra/http/routes/index.ts index 8f3bf37..2ae3a26 100644 --- a/src/shared/infra/http/routes/index.ts +++ b/src/shared/infra/http/routes/index.ts @@ -1,4 +1,5 @@ import { adminRoutes } from '@modules/users/infra/http/routes/admin.routes'; +import { passwordRoutes } from '@modules/users/infra/http/routes/password.routes'; import { profileRoutes } from '@modules/users/infra/http/routes/profile.routes'; import { sessionsRoutes } from '@modules/users/infra/http/routes/sessions.routes'; import { usersRoutes } from '@modules/users/infra/http/routes/users.routes'; @@ -7,8 +8,9 @@ import { Router } from 'express'; const routes = Router(); routes.use('/users', usersRoutes); -routes.use('/sessions', sessionsRoutes); routes.use('/admin', adminRoutes); routes.use('/profile', profileRoutes); +routes.use('/password', passwordRoutes); +routes.use(sessionsRoutes); export { routes }; From 2064c42a4fc109804b28f8a96e22d4ddfec9d336 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 19:22:28 -0300 Subject: [PATCH 40/92] feat: send forgot and reset password controllers and routes --- .../controllers/ForgotPasswordController.ts | 20 +++++++++++ .../controllers/ResetPasswordController.ts | 18 ++++++++++ .../infra/http/routes/password.routes.ts | 33 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 src/modules/users/infra/http/controllers/ForgotPasswordController.ts create mode 100644 src/modules/users/infra/http/controllers/ResetPasswordController.ts create mode 100644 src/modules/users/infra/http/routes/password.routes.ts diff --git a/src/modules/users/infra/http/controllers/ForgotPasswordController.ts b/src/modules/users/infra/http/controllers/ForgotPasswordController.ts new file mode 100644 index 0000000..91afce7 --- /dev/null +++ b/src/modules/users/infra/http/controllers/ForgotPasswordController.ts @@ -0,0 +1,20 @@ +import { SendForgotPasswordEmailService } from '@modules/users/services/SendForgotPasswordEmailService'; +import { Request, Response } from 'express'; + +import { container } from 'tsyringe'; + +class ForgotPasswordController { + async handle(request: Request, response: Response): Promise { + const { email } = request.body; + + const sendForgotPassword = container.resolve( + SendForgotPasswordEmailService, + ); + + await sendForgotPassword.execute({ email }); + + return response.status(204).json(); + } +} + +export { ForgotPasswordController }; diff --git a/src/modules/users/infra/http/controllers/ResetPasswordController.ts b/src/modules/users/infra/http/controllers/ResetPasswordController.ts new file mode 100644 index 0000000..bb5e8ec --- /dev/null +++ b/src/modules/users/infra/http/controllers/ResetPasswordController.ts @@ -0,0 +1,18 @@ +import { ResetPasswordService } from '@modules/users/services/ResetPasswordService'; +import { Request, Response } from 'express'; + +import { container } from 'tsyringe'; + +class ResetPasswordController { + async handle(request: Request, response: Response): Promise { + const { token, password } = request.body; + + const resetPassword = container.resolve(ResetPasswordService); + + await resetPassword.execute({ token, password }); + + return response.status(204).json(); + } +} + +export { ResetPasswordController }; diff --git a/src/modules/users/infra/http/routes/password.routes.ts b/src/modules/users/infra/http/routes/password.routes.ts new file mode 100644 index 0000000..39e0937 --- /dev/null +++ b/src/modules/users/infra/http/routes/password.routes.ts @@ -0,0 +1,33 @@ +import { celebrate, Segments, Joi } from 'celebrate'; +import { Router } from 'express'; +import { ForgotPasswordController } from '../controllers/ForgotPasswordController'; +import { ResetPasswordController } from '../controllers/ResetPasswordController'; + +const passwordRoutes = Router(); + +const forgotPasswordController = new ForgotPasswordController(); +const resetPasswordController = new ResetPasswordController(); + +passwordRoutes.post( + '/forgot', + celebrate({ + [Segments.BODY]: { + email: Joi.string().required().email(), + }, + }), + forgotPasswordController.handle, +); + +passwordRoutes.post( + '/reset', + celebrate({ + [Segments.BODY]: { + token: Joi.string().uuid().required(), + password: Joi.string().optional().min(6).max(18), + password_confirmation: Joi.string().required().valid(Joi.ref('password')), + }, + }), + resetPasswordController.handle, +); + +export { passwordRoutes }; From 99a57b43cff601277f03e3f32a91230d06da1ca0 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 19 Jan 2022 19:24:30 -0300 Subject: [PATCH 41/92] chore: adding column in usertokens migration --- .../typeorm/migrations/1642610997984-CreateUsersTokens.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/shared/infra/typeorm/migrations/1642610997984-CreateUsersTokens.ts b/src/shared/infra/typeorm/migrations/1642610997984-CreateUsersTokens.ts index 20a6e5e..ecee940 100644 --- a/src/shared/infra/typeorm/migrations/1642610997984-CreateUsersTokens.ts +++ b/src/shared/infra/typeorm/migrations/1642610997984-CreateUsersTokens.ts @@ -4,16 +4,20 @@ export class CreateUsersTokens1642610997984 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { await queryRunner.createTable( new Table({ - name: 'users_tokens', + name: 'user_tokens', columns: [ { name: 'id', type: 'uuid', isPrimary: true, + generationStrategy: 'uuid', + default: 'uuid_generate_v4()', }, { name: 'token', type: 'uuid', + generationStrategy: 'uuid', + default: 'uuid_generate_v4()', }, { name: 'user_id', @@ -45,6 +49,6 @@ export class CreateUsersTokens1642610997984 implements MigrationInterface { } public async down(queryRunner: QueryRunner): Promise { - await queryRunner.dropTable('users_tokens'); + await queryRunner.dropTable('user_tokens'); } } From 2d0edaf02fb75ab18a84f8d310029f323fde9f67 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 03:02:14 -0300 Subject: [PATCH 42/92] feat: ethereal fake email service and tamplate handlebars --- src/config/mail/EtherealMail.ts | 65 +++++++++++++++++++ src/config/mail/HandlebarsMailTemplate.ts | 25 +++++++ .../SendForgotPasswordEmailService.ts | 26 +++++++- src/modules/users/views/forgot_password.hbs | 25 +++++++ 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/config/mail/EtherealMail.ts create mode 100644 src/config/mail/HandlebarsMailTemplate.ts diff --git a/src/config/mail/EtherealMail.ts b/src/config/mail/EtherealMail.ts new file mode 100644 index 0000000..272432d --- /dev/null +++ b/src/config/mail/EtherealMail.ts @@ -0,0 +1,65 @@ +import nodemailer from 'nodemailer'; +import { HandlebarsMailTemplate } from './HandlebarsMailTemplate'; + +interface IMailContact { + name: string; + email: string; +} + +interface ITemplateVariable { + [key: string]: string | number; +} + +interface IParseMailTemplate { + file: string; + variables: ITemplateVariable; +} + +interface ISendMail { + from?: IMailContact; + to: IMailContact; + subject: string; + templateData: IParseMailTemplate; +} + +class EtherealMail { + static async sendMail({ + to, + from, + subject, + templateData, + }: ISendMail): Promise { + const account = await nodemailer.createTestAccount(); + + const mailTemplate = new HandlebarsMailTemplate(); + + const transporter = nodemailer.createTransport({ + host: account.smtp.host, + port: account.smtp.port, + secure: account.smtp.secure, + auth: { + user: account.user, + pass: account.pass, + }, + }); + + const message = await transporter.sendMail({ + from: { + name: from?.name || 'Equipe Achados e Perdidos', + address: from?.email || 'equipe@eap.com.br', + }, + to: { + name: to.name, + address: to.email, + }, + subject, + html: await mailTemplate.parse(templateData), + }); + + console.log('Message sent: %s', message.messageId); + + console.log('Preview URL: %s', nodemailer.getTestMessageUrl(message)); + } +} + +export { EtherealMail }; diff --git a/src/config/mail/HandlebarsMailTemplate.ts b/src/config/mail/HandlebarsMailTemplate.ts new file mode 100644 index 0000000..b748e4f --- /dev/null +++ b/src/config/mail/HandlebarsMailTemplate.ts @@ -0,0 +1,25 @@ +import handlebars from 'handlebars'; +import fs from 'fs'; + +interface ITemplateVariable { + [key: string]: string | number; +} + +interface IParseMailTemplate { + file: string; + variables: ITemplateVariable; +} + +class HandlebarsMailTemplate { + async parse({ file, variables }: IParseMailTemplate): Promise { + const templateFileContent = await fs.promises.readFile(file, { + encoding: 'utf8', + }); + + const parseTemplate = handlebars.compile(templateFileContent); + + return parseTemplate(variables); + } +} + +export { HandlebarsMailTemplate }; diff --git a/src/modules/users/services/SendForgotPasswordEmailService.ts b/src/modules/users/services/SendForgotPasswordEmailService.ts index ee65b90..83f658e 100644 --- a/src/modules/users/services/SendForgotPasswordEmailService.ts +++ b/src/modules/users/services/SendForgotPasswordEmailService.ts @@ -1,3 +1,5 @@ +import path from 'path'; +import { EtherealMail } from '@config/mail/EtherealMail'; import { AppError } from '@shared/errors/AppError'; import { inject, injectable } from 'tsyringe'; import { IUsersRepository } from '../domain/repositories/IUsersRepository'; @@ -23,9 +25,29 @@ class SendForgotPasswordEmailService { throw new AppError('User not found.', 404); } - const token = await this.userTokensRepository.generate(user.id); + const { token } = await this.userTokensRepository.generate(user.id); - console.log(token); + const forgotPasswordTemplate = path.resolve( + __dirname, + '..', + 'views', + 'forgot_password.hbs', + ); + + await EtherealMail.sendMail({ + to: { + name: user.email, + email: user.email, + }, + subject: '[API Achado e Perdidos] Recuperação de senha', + templateData: { + file: forgotPasswordTemplate, + variables: { + name: user.name, + link: `${process.env.APP_WEB_URL}/reset-password?token=${token}`, + }, + }, + }); } } diff --git a/src/modules/users/views/forgot_password.hbs b/src/modules/users/views/forgot_password.hbs index e69de29..98a9306 100644 --- a/src/modules/users/views/forgot_password.hbs +++ b/src/modules/users/views/forgot_password.hbs @@ -0,0 +1,25 @@ + + +
+

Olá, {{name}}.

+
+ +

Recebemos uma solicitação de redefinição de senha para a sua conta de usuário.

+

Se realmente foi você que solicitou a redefinição, clique no link abaixo para escolher uma nova senha.

+ +

+ Nova senha +

+ +

Caso você não tenha realizado essa solicitação, descarte este email.

+
+ +

Obrigado!

+
From 99dfca9f49d054262f9b93cf7f37a05ed8b5e7ff Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 03:03:38 -0300 Subject: [PATCH 43/92] chore: adding dependencies for fake email --- .env.example | 1 + package.json | 3 ++ .../repositories/IUsersTokensRepository.ts | 2 +- .../repositories/UserTokensRepository.ts | 2 +- yarn.lock | 41 ++++++++++++++++++- 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 39ace0d..49a0161 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,3 @@ PORT = 3333 APP_SECRET = 91cf4aa79dbb713fbf551ce3efa9c12d +APP_WEB_URL = http://localhost:3000 diff --git a/package.json b/package.json index b8a675b..210950f 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@types/jsonwebtoken": "^8.5.8", "@types/multer": "^1.4.7", "@types/node": "^17.0.8", + "@types/nodemailer": "^6.4.4", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.10.0", "@typescript-eslint/parser": "^5.10.0", @@ -38,8 +39,10 @@ "dotenv": "^14.2.0", "express": "^4.17.2", "express-async-errors": "^3.1.1", + "handlebars": "^4.7.7", "jsonwebtoken": "^8.5.1", "multer": "^1.4.4", + "nodemailer": "^6.7.2", "pg": "^8.7.1", "reflect-metadata": "^0.1.13", "tsyringe": "^4.6.0", diff --git a/src/modules/users/domain/repositories/IUsersTokensRepository.ts b/src/modules/users/domain/repositories/IUsersTokensRepository.ts index 4ef8dc1..5d82306 100644 --- a/src/modules/users/domain/repositories/IUsersTokensRepository.ts +++ b/src/modules/users/domain/repositories/IUsersTokensRepository.ts @@ -2,7 +2,7 @@ import { IUserToken } from '../models/IUserToken'; interface IUserTokensRepository { findByToken(token: string): Promise; - generate(user_id: string): Promise; + generate(user_id: string): Promise; } export { IUserTokensRepository }; diff --git a/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts b/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts index b41ee57..267e9be 100644 --- a/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts +++ b/src/modules/users/infra/typeorm/repositories/UserTokensRepository.ts @@ -16,7 +16,7 @@ class UserTokensRepository implements IUserTokensRepository { return userToken; } - async generate(user_id: string): Promise { + async generate(user_id: string): Promise { const userToken = this.repository.create({ user_id }); await this.repository.save(userToken); diff --git a/yarn.lock b/yarn.lock index 5e27c44..96ba5b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -188,6 +188,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b" integrity sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg== +"@types/nodemailer@^6.4.4": + version "6.4.4" + resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.4.tgz#c265f7e7a51df587597b3a49a023acaf0c741f4b" + integrity sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw== + dependencies: + "@types/node" "*" + "@types/qs@*": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -1145,6 +1152,18 @@ globby@^11.0.4: merge2 "^1.4.1" slash "^3.0.0" +handlebars@^4.7.7: + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -1562,6 +1581,11 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + node-addon-api@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" @@ -1574,6 +1598,11 @@ node-fetch@^2.6.5: dependencies: whatwg-url "^5.0.0" +nodemailer@^6.7.2: + version "6.7.2" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0" + integrity sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q== + nopt@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" @@ -2032,7 +2061,7 @@ source-map-support@^0.5.12, source-map-support@^0.5.17: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.6.0: +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== @@ -2291,6 +2320,11 @@ typescript@^4.5.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== +uglify-js@^3.1.4: + version "3.14.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.5.tgz#cdabb7d4954231d80cb4a927654c4655e51f4859" + integrity sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -2360,6 +2394,11 @@ word-wrap@^1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" From 540a6a2f7d6abc6a181f1960e8a055bf69bbfe80 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 12:38:02 -0300 Subject: [PATCH 44/92] chore: create migration categories --- .../migrations/1642478743972-CreateUser.ts | 1 + .../1642659878411-CreateCategories.ts | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/shared/infra/typeorm/migrations/1642659878411-CreateCategories.ts diff --git a/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts b/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts index aafedd5..97a7e6f 100644 --- a/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts +++ b/src/shared/infra/typeorm/migrations/1642478743972-CreateUser.ts @@ -18,6 +18,7 @@ export class CreateUser1642478743972 implements MigrationInterface { { name: 'email', type: 'varchar', + isUnique: true, }, { name: 'password', diff --git a/src/shared/infra/typeorm/migrations/1642659878411-CreateCategories.ts b/src/shared/infra/typeorm/migrations/1642659878411-CreateCategories.ts new file mode 100644 index 0000000..25f688f --- /dev/null +++ b/src/shared/infra/typeorm/migrations/1642659878411-CreateCategories.ts @@ -0,0 +1,41 @@ +import { MigrationInterface, QueryRunner, Table } from 'typeorm'; + +export class CreateCategories1642659878411 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: 'categories', + columns: [ + { + name: 'id', + type: 'uuid', + isPrimary: true, + }, + { + name: 'name', + type: 'varchar', + isUnique: true, + }, + { + name: 'description', + type: 'varchar', + }, + { + name: 'created_at', + type: 'timestamp', + default: 'now()', + }, + { + name: 'updated_at', + type: 'timestamp', + default: 'now()', + }, + ], + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable('categories'); + } +} From 6011971769dfe9e3985f450d7ddfab66f433d51b Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 12:50:21 -0300 Subject: [PATCH 45/92] feat: create category --- .../domain/dtos/ICreateCategoryDTO.ts | 6 ++++ .../categories/domain/models/ICategory.ts | 9 +++++ .../repositories/ICategoriesRepository.ts | 9 +++++ .../controllers/CreateCategoryController.ts | 20 +++++++++++ .../infra/http/routes/categories.routes.ts | 24 +++++++++++++ .../infra/typeorm/entities/Category.ts | 36 +++++++++++++++++++ .../repositories/CategoriesRepository.ts | 30 ++++++++++++++++ .../services/CreateCategoryService.ts | 27 ++++++++++++++ src/shared/container/index.ts | 7 ++++ src/shared/infra/http/routes/index.ts | 2 ++ 10 files changed, 170 insertions(+) create mode 100644 src/modules/categories/domain/dtos/ICreateCategoryDTO.ts create mode 100644 src/modules/categories/domain/models/ICategory.ts create mode 100644 src/modules/categories/domain/repositories/ICategoriesRepository.ts create mode 100644 src/modules/categories/infra/http/controllers/CreateCategoryController.ts create mode 100644 src/modules/categories/infra/http/routes/categories.routes.ts create mode 100644 src/modules/categories/infra/typeorm/entities/Category.ts create mode 100644 src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts create mode 100644 src/modules/categories/services/CreateCategoryService.ts diff --git a/src/modules/categories/domain/dtos/ICreateCategoryDTO.ts b/src/modules/categories/domain/dtos/ICreateCategoryDTO.ts new file mode 100644 index 0000000..59df107 --- /dev/null +++ b/src/modules/categories/domain/dtos/ICreateCategoryDTO.ts @@ -0,0 +1,6 @@ +interface ICreateCategoryDTO { + name: string; + description: string; +} + +export { ICreateCategoryDTO }; diff --git a/src/modules/categories/domain/models/ICategory.ts b/src/modules/categories/domain/models/ICategory.ts new file mode 100644 index 0000000..94454d0 --- /dev/null +++ b/src/modules/categories/domain/models/ICategory.ts @@ -0,0 +1,9 @@ +interface ICategory { + id: string; + name: string; + description: string; + created_at: Date; + updated_at: Date; +} + +export { ICategory }; diff --git a/src/modules/categories/domain/repositories/ICategoriesRepository.ts b/src/modules/categories/domain/repositories/ICategoriesRepository.ts new file mode 100644 index 0000000..bf9b183 --- /dev/null +++ b/src/modules/categories/domain/repositories/ICategoriesRepository.ts @@ -0,0 +1,9 @@ +import { ICreateCategoryDTO } from '../dtos/ICreateCategoryDTO'; +import { ICategory } from '../models/ICategory'; + +interface ICategoriesRepository { + create(data: ICreateCategoryDTO): Promise; + findByName(name: string): Promise; +} + +export { ICategoriesRepository }; diff --git a/src/modules/categories/infra/http/controllers/CreateCategoryController.ts b/src/modules/categories/infra/http/controllers/CreateCategoryController.ts new file mode 100644 index 0000000..8e84947 --- /dev/null +++ b/src/modules/categories/infra/http/controllers/CreateCategoryController.ts @@ -0,0 +1,20 @@ +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; +import { CreateCategoryService } from '@modules/categories/services/CreateCategoryService'; + +class CreateCategoryController { + async handle(request: Request, response: Response): Promise { + const { name, description } = request.body; + + const createCategoryService = container.resolve(CreateCategoryService); + + await createCategoryService.execute({ + name, + description, + }); + + return response.status(201).send(); + } +} + +export { CreateCategoryController }; diff --git a/src/modules/categories/infra/http/routes/categories.routes.ts b/src/modules/categories/infra/http/routes/categories.routes.ts new file mode 100644 index 0000000..2176af3 --- /dev/null +++ b/src/modules/categories/infra/http/routes/categories.routes.ts @@ -0,0 +1,24 @@ +import ensureAdmin from '@shared/infra/http/middlewares/ensureAdmin'; +import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; +import { celebrate, Segments, Joi } from 'celebrate'; +import { Router } from 'express'; +import { CreateCategoryController } from '../controllers/CreateCategoryController'; + +const categoriesRoutes = Router(); + +const createCategoryController = new CreateCategoryController(); + +categoriesRoutes.post( + '/', + ensureAuthenticated, + ensureAdmin, + celebrate({ + [Segments.BODY]: { + name: Joi.string().required(), + description: Joi.string().required(), + }, + }), + createCategoryController.handle, +); + +export { categoriesRoutes }; diff --git a/src/modules/categories/infra/typeorm/entities/Category.ts b/src/modules/categories/infra/typeorm/entities/Category.ts new file mode 100644 index 0000000..676b855 --- /dev/null +++ b/src/modules/categories/infra/typeorm/entities/Category.ts @@ -0,0 +1,36 @@ +import { ICategory } from '@modules/categories/domain/models/ICategory'; +import { + Column, + CreateDateColumn, + Entity, + PrimaryColumn, + UpdateDateColumn, +} from 'typeorm'; + +import { v4 as uuidV4 } from 'uuid'; + +@Entity('categories') +class Category implements ICategory { + @PrimaryColumn() + id: string; + + @Column() + name: string; + + @Column() + description: string; + + @CreateDateColumn() + created_at: Date; + + @UpdateDateColumn() + updated_at: Date; + + constructor() { + if (!this.id) { + this.id = uuidV4(); + } + } +} + +export { Category }; diff --git a/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts b/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts new file mode 100644 index 0000000..9f6c3b1 --- /dev/null +++ b/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts @@ -0,0 +1,30 @@ +import { ICreateCategoryDTO } from '@modules/categories/domain/dtos/ICreateCategoryDTO'; +import { ICategory } from '@modules/categories/domain/models/ICategory'; +import { ICategoriesRepository } from '@modules/categories/domain/repositories/ICategoriesRepository'; +import { getRepository, Repository } from 'typeorm'; +import { Category } from '../entities/Category'; + +class CategoriesRepository implements ICategoriesRepository { + private repository: Repository; + + constructor() { + this.repository = getRepository(Category); + } + + async findByName(name: string): Promise { + const category = await this.repository.findOne({ name }); + + return category; + } + + async create({ name, description }: ICreateCategoryDTO): Promise { + const createCategory = this.repository.create({ + name, + description, + }); + + await this.repository.save(createCategory); + } +} + +export { CategoriesRepository }; diff --git a/src/modules/categories/services/CreateCategoryService.ts b/src/modules/categories/services/CreateCategoryService.ts new file mode 100644 index 0000000..ced3686 --- /dev/null +++ b/src/modules/categories/services/CreateCategoryService.ts @@ -0,0 +1,27 @@ +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { ICreateCategoryDTO } from '../domain/dtos/ICreateCategoryDTO'; +import { ICategoriesRepository } from '../domain/repositories/ICategoriesRepository'; + +@injectable() +class CreateCategoryService { + constructor( + @inject('CategoriesRepository') + private categoriesRepository: ICategoriesRepository, + ) {} + + async execute({ name, description }: ICreateCategoryDTO): Promise { + const categoryExists = await this.categoriesRepository.findByName(name); + + if (categoryExists) { + throw new AppError('This category already exists.'); + } + + this.categoriesRepository.create({ + name, + description, + }); + } +} + +export { CreateCategoryService }; diff --git a/src/shared/container/index.ts b/src/shared/container/index.ts index 7327118..a59260c 100644 --- a/src/shared/container/index.ts +++ b/src/shared/container/index.ts @@ -6,6 +6,8 @@ import '@modules/users/providers'; import { UserTokensRepository } from '@modules/users/infra/typeorm/repositories/UserTokensRepository'; import { IUserTokensRepository } from '@modules/users/domain/repositories/IUsersTokensRepository'; +import { ICategoriesRepository } from '@modules/categories/domain/repositories/ICategoriesRepository'; +import { CategoriesRepository } from '@modules/categories/infra/typeorm/repositories/CategoriesRepository'; container.registerSingleton( 'UsersRepository', @@ -16,3 +18,8 @@ container.registerSingleton( 'UserTokensRepository', UserTokensRepository, ); + +container.registerSingleton( + 'CategoriesRepository', + CategoriesRepository, +); diff --git a/src/shared/infra/http/routes/index.ts b/src/shared/infra/http/routes/index.ts index 2ae3a26..8ce95ee 100644 --- a/src/shared/infra/http/routes/index.ts +++ b/src/shared/infra/http/routes/index.ts @@ -1,3 +1,4 @@ +import { categoriesRoutes } from '@modules/categories/infra/http/routes/categories.routes'; import { adminRoutes } from '@modules/users/infra/http/routes/admin.routes'; import { passwordRoutes } from '@modules/users/infra/http/routes/password.routes'; import { profileRoutes } from '@modules/users/infra/http/routes/profile.routes'; @@ -11,6 +12,7 @@ routes.use('/users', usersRoutes); routes.use('/admin', adminRoutes); routes.use('/profile', profileRoutes); routes.use('/password', passwordRoutes); +routes.use('/categories', categoriesRoutes); routes.use(sessionsRoutes); export { routes }; From a0fa8a9daf88f5bf518c758878c0eeb1e7d4ccae Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 13:31:10 -0300 Subject: [PATCH 46/92] feat: list categories --- .../repositories/ICategoriesRepository.ts | 1 + .../controllers/ListCategoriesController.ts | 15 +++++++++++++++ .../infra/http/routes/categories.routes.ts | 9 +++++++++ .../repositories/CategoriesRepository.ts | 5 +++++ .../services/ListCategoriesService.ts | 19 +++++++++++++++++++ 5 files changed, 49 insertions(+) create mode 100644 src/modules/categories/infra/http/controllers/ListCategoriesController.ts create mode 100644 src/modules/categories/services/ListCategoriesService.ts diff --git a/src/modules/categories/domain/repositories/ICategoriesRepository.ts b/src/modules/categories/domain/repositories/ICategoriesRepository.ts index bf9b183..878e9af 100644 --- a/src/modules/categories/domain/repositories/ICategoriesRepository.ts +++ b/src/modules/categories/domain/repositories/ICategoriesRepository.ts @@ -4,6 +4,7 @@ import { ICategory } from '../models/ICategory'; interface ICategoriesRepository { create(data: ICreateCategoryDTO): Promise; findByName(name: string): Promise; + list(): Promise; } export { ICategoriesRepository }; diff --git a/src/modules/categories/infra/http/controllers/ListCategoriesController.ts b/src/modules/categories/infra/http/controllers/ListCategoriesController.ts new file mode 100644 index 0000000..32abc4e --- /dev/null +++ b/src/modules/categories/infra/http/controllers/ListCategoriesController.ts @@ -0,0 +1,15 @@ +import { ListCategoriesService } from '@modules/categories/services/ListCategoriesService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class ListCategoriesController { + async handle(request: Request, response: Response): Promise { + const listCategories = container.resolve(ListCategoriesService); + + const categories = await listCategories.execute(); + + return response.json(categories); + } +} + +export { ListCategoriesController }; diff --git a/src/modules/categories/infra/http/routes/categories.routes.ts b/src/modules/categories/infra/http/routes/categories.routes.ts index 2176af3..ef2be26 100644 --- a/src/modules/categories/infra/http/routes/categories.routes.ts +++ b/src/modules/categories/infra/http/routes/categories.routes.ts @@ -2,11 +2,13 @@ import ensureAdmin from '@shared/infra/http/middlewares/ensureAdmin'; import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; import { celebrate, Segments, Joi } from 'celebrate'; import { Router } from 'express'; +import { ListCategoriesController } from '../controllers/ListCategoriesController'; import { CreateCategoryController } from '../controllers/CreateCategoryController'; const categoriesRoutes = Router(); const createCategoryController = new CreateCategoryController(); +const listCategoriesController = new ListCategoriesController(); categoriesRoutes.post( '/', @@ -21,4 +23,11 @@ categoriesRoutes.post( createCategoryController.handle, ); +categoriesRoutes.get( + '/', + ensureAuthenticated, + ensureAdmin, + listCategoriesController.handle, +); + export { categoriesRoutes }; diff --git a/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts b/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts index 9f6c3b1..00e95e5 100644 --- a/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts +++ b/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts @@ -11,6 +11,11 @@ class CategoriesRepository implements ICategoriesRepository { this.repository = getRepository(Category); } + async list(): Promise { + const categories = await this.repository.find(); + return categories; + } + async findByName(name: string): Promise { const category = await this.repository.findOne({ name }); diff --git a/src/modules/categories/services/ListCategoriesService.ts b/src/modules/categories/services/ListCategoriesService.ts new file mode 100644 index 0000000..24ca146 --- /dev/null +++ b/src/modules/categories/services/ListCategoriesService.ts @@ -0,0 +1,19 @@ +import { inject, injectable } from 'tsyringe'; +import { ICategory } from '../domain/models/ICategory'; +import { ICategoriesRepository } from '../domain/repositories/ICategoriesRepository'; + +@injectable() +class ListCategoriesService { + constructor( + @inject('CategoriesRepository') + private categoriesRepository: ICategoriesRepository, + ) {} + + async execute(): Promise { + const categories = await this.categoriesRepository.list(); + + return categories; + } +} + +export { ListCategoriesService }; From b8865806ad96f82cc76d5712783cc30b638b9ee3 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 14:24:55 -0300 Subject: [PATCH 47/92] feat: delete category --- .../repositories/ICategoriesRepository.ts | 3 +++ .../controllers/DeleteCategoryController.ts | 17 ++++++++++++ .../infra/http/routes/categories.routes.ts | 9 +++++++ .../repositories/CategoriesRepository.ts | 14 ++++++++++ .../services/DeleteCategoryService.ts | 27 +++++++++++++++++++ 5 files changed, 70 insertions(+) create mode 100644 src/modules/categories/infra/http/controllers/DeleteCategoryController.ts create mode 100644 src/modules/categories/services/DeleteCategoryService.ts diff --git a/src/modules/categories/domain/repositories/ICategoriesRepository.ts b/src/modules/categories/domain/repositories/ICategoriesRepository.ts index 878e9af..5b0bfef 100644 --- a/src/modules/categories/domain/repositories/ICategoriesRepository.ts +++ b/src/modules/categories/domain/repositories/ICategoriesRepository.ts @@ -5,6 +5,9 @@ interface ICategoriesRepository { create(data: ICreateCategoryDTO): Promise; findByName(name: string): Promise; list(): Promise; + findById(id: string): Promise; + findByDelete(id: string): Promise; + save(category: ICategory): Promise; } export { ICategoriesRepository }; diff --git a/src/modules/categories/infra/http/controllers/DeleteCategoryController.ts b/src/modules/categories/infra/http/controllers/DeleteCategoryController.ts new file mode 100644 index 0000000..e78f721 --- /dev/null +++ b/src/modules/categories/infra/http/controllers/DeleteCategoryController.ts @@ -0,0 +1,17 @@ +import { DeleteCategoryService } from '@modules/categories/services/DeleteCategoryService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class DeleteCategoryController { + async handle(request: Request, response: Response): Promise { + const { id } = request.params; + + const deleteCategoryService = container.resolve(DeleteCategoryService); + + await deleteCategoryService.execute({ id }); + + return response.status(204).send(); + } +} + +export { DeleteCategoryController }; diff --git a/src/modules/categories/infra/http/routes/categories.routes.ts b/src/modules/categories/infra/http/routes/categories.routes.ts index ef2be26..3e70091 100644 --- a/src/modules/categories/infra/http/routes/categories.routes.ts +++ b/src/modules/categories/infra/http/routes/categories.routes.ts @@ -4,11 +4,13 @@ import { celebrate, Segments, Joi } from 'celebrate'; import { Router } from 'express'; import { ListCategoriesController } from '../controllers/ListCategoriesController'; import { CreateCategoryController } from '../controllers/CreateCategoryController'; +import { DeleteCategoryController } from '../controllers/DeleteCategoryController'; const categoriesRoutes = Router(); const createCategoryController = new CreateCategoryController(); const listCategoriesController = new ListCategoriesController(); +const deleteCategoryController = new DeleteCategoryController(); categoriesRoutes.post( '/', @@ -30,4 +32,11 @@ categoriesRoutes.get( listCategoriesController.handle, ); +categoriesRoutes.delete( + '/:id', + ensureAuthenticated, + ensureAdmin, + deleteCategoryController.handle, +); + export { categoriesRoutes }; diff --git a/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts b/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts index 00e95e5..4203bd0 100644 --- a/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts +++ b/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts @@ -11,6 +11,20 @@ class CategoriesRepository implements ICategoriesRepository { this.repository = getRepository(Category); } + async findById(id: string): Promise { + const category = await this.repository.findOne(id); + + return category; + } + + async findByDelete(id: string): Promise { + await this.repository.delete(id); + } + + async save(category: ICategory): Promise { + await this.repository.save(category); + } + async list(): Promise { const categories = await this.repository.find(); return categories; diff --git a/src/modules/categories/services/DeleteCategoryService.ts b/src/modules/categories/services/DeleteCategoryService.ts new file mode 100644 index 0000000..2af6b9c --- /dev/null +++ b/src/modules/categories/services/DeleteCategoryService.ts @@ -0,0 +1,27 @@ +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { ICategoriesRepository } from '../domain/repositories/ICategoriesRepository'; + +interface IRequest { + id: string; +} + +@injectable() +class DeleteCategoryService { + constructor( + @inject('CategoriesRepository') + private categoriesRepository: ICategoriesRepository, + ) {} + + async execute({ id }: IRequest): Promise { + const category = await this.categoriesRepository.findById(id); + + if (!category) { + throw new AppError('Category not found.', 404); + } + + await this.categoriesRepository.findByDelete(id); + } +} + +export { DeleteCategoryService }; From dd91ccbb3b31c3fc9498f99f1996fcb7a2e8407d Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 15:08:02 -0300 Subject: [PATCH 48/92] feat: update category --- .../controllers/UpdateCategoryController.ts | 22 +++++++++++ .../infra/http/routes/categories.routes.ts | 9 +++++ .../services/UpdateCategoryService.ts | 38 +++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 src/modules/categories/infra/http/controllers/UpdateCategoryController.ts create mode 100644 src/modules/categories/services/UpdateCategoryService.ts diff --git a/src/modules/categories/infra/http/controllers/UpdateCategoryController.ts b/src/modules/categories/infra/http/controllers/UpdateCategoryController.ts new file mode 100644 index 0000000..7af3fd7 --- /dev/null +++ b/src/modules/categories/infra/http/controllers/UpdateCategoryController.ts @@ -0,0 +1,22 @@ +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; +import { UpdateCategoryService } from '@modules/categories/services/UpdateCategoryService'; + +class UpdateCategoryController { + async handle(request: Request, response: Response): Promise { + const { id } = request.params; + const { name, description } = request.body; + + const updateCategoryService = container.resolve(UpdateCategoryService); + + await updateCategoryService.execute({ + id, + name, + description, + }); + + return response.send(); + } +} + +export { UpdateCategoryController }; diff --git a/src/modules/categories/infra/http/routes/categories.routes.ts b/src/modules/categories/infra/http/routes/categories.routes.ts index 3e70091..0dd2633 100644 --- a/src/modules/categories/infra/http/routes/categories.routes.ts +++ b/src/modules/categories/infra/http/routes/categories.routes.ts @@ -5,12 +5,14 @@ import { Router } from 'express'; import { ListCategoriesController } from '../controllers/ListCategoriesController'; import { CreateCategoryController } from '../controllers/CreateCategoryController'; import { DeleteCategoryController } from '../controllers/DeleteCategoryController'; +import { UpdateCategoryController } from '../controllers/UpdateCategoryController'; const categoriesRoutes = Router(); const createCategoryController = new CreateCategoryController(); const listCategoriesController = new ListCategoriesController(); const deleteCategoryController = new DeleteCategoryController(); +const updateCategoryController = new UpdateCategoryController(); categoriesRoutes.post( '/', @@ -39,4 +41,11 @@ categoriesRoutes.delete( deleteCategoryController.handle, ); +categoriesRoutes.put( + '/:id', + ensureAuthenticated, + ensureAdmin, + updateCategoryController.handle, +); + export { categoriesRoutes }; diff --git a/src/modules/categories/services/UpdateCategoryService.ts b/src/modules/categories/services/UpdateCategoryService.ts new file mode 100644 index 0000000..b3e9dab --- /dev/null +++ b/src/modules/categories/services/UpdateCategoryService.ts @@ -0,0 +1,38 @@ +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { ICategoriesRepository } from '../domain/repositories/ICategoriesRepository'; + +interface IResqust { + id: string; + name: string; + description: string; +} + +@injectable() +class UpdateCategoryService { + constructor( + @inject('CategoriesRepository') + private categoriesRepository: ICategoriesRepository, + ) {} + + async execute({ id, name, description }: IResqust): Promise { + const category = await this.categoriesRepository.findById(id); + + if (!category) { + throw new AppError('Category not found', 404); + } + + const categoryName = await this.categoriesRepository.findByName(name); + + if (categoryName && name !== category.name) { + throw new AppError('There is already one category with this name.'); + } + + category.name = name; + category.description = description; + + await this.categoriesRepository.save(category); + } +} + +export { UpdateCategoryService }; From 8cfef4142ca40787e26bee48b1ff88763f053ebe Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 21:40:56 -0300 Subject: [PATCH 49/92] chore: adding migration objetcs --- .../migrations/1642708699976-CreateObject.ts | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts diff --git a/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts b/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts new file mode 100644 index 0000000..f4cfc9c --- /dev/null +++ b/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts @@ -0,0 +1,68 @@ +import { MigrationInterface, QueryRunner, Table } from 'typeorm'; + +export class CreateObject1642708699976 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "CREATE TYPE typeEnum AS ENUM('Perdido', 'Achado')", + ); + await queryRunner.createTable( + new Table({ + name: 'objects', + columns: [ + { + name: 'id', + type: 'uuid', + isPrimary: true, + }, + { + name: 'name', + type: 'varchar', + }, + { + name: 'comments', + type: 'varchar', + isNullable: true, + }, + { + name: 'available', + type: 'boolean', + default: true, + }, + { + name: 'type', + type: 'typeEnum', + }, + { + name: 'category_id', + type: 'uuid', + isNullable: true, + }, + { + name: 'created_at', + type: 'timestamp', + default: 'now()', + }, + { + name: 'updated_at', + type: 'timestamp', + default: 'now()', + }, + ], + foreignKeys: [ + { + name: 'FKCategoryObject', + referencedTableName: 'categories', + referencedColumnNames: ['id'], + columnNames: ['category_id'], + onDelete: 'SET NULL', + onUpdate: 'SET NULL', + }, + ], + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable('objects'); + } +} From 28a10baf671988cbf7ea6af3e77b42caaef783a2 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 21:42:03 -0300 Subject: [PATCH 50/92] feat: create object --- .../objects/domain/dtos/ICreateObjectDTO.ts | 10 ++++ src/modules/objects/domain/models/IObject.ts | 16 ++++++ .../domain/repositories/IObjectsRepository.ts | 8 +++ .../controllers/CreateObjectController.ts | 22 ++++++++ .../infra/http/routes/objects.routes.ts | 11 ++++ .../infra/typeorm/entities/ObjectLostFound.ts | 55 +++++++++++++++++++ .../infra/typeorm/entities/TypeEnum.ts | 4 ++ .../typeorm/repositories/ObjectsRepository.ts | 33 +++++++++++ .../objects/services/CreateObjectService.ts | 30 ++++++++++ src/shared/container/index.ts | 7 +++ src/shared/infra/http/routes/index.ts | 2 + 11 files changed, 198 insertions(+) create mode 100644 src/modules/objects/domain/dtos/ICreateObjectDTO.ts create mode 100644 src/modules/objects/domain/models/IObject.ts create mode 100644 src/modules/objects/domain/repositories/IObjectsRepository.ts create mode 100644 src/modules/objects/infra/http/controllers/CreateObjectController.ts create mode 100644 src/modules/objects/infra/http/routes/objects.routes.ts create mode 100644 src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts create mode 100644 src/modules/objects/infra/typeorm/entities/TypeEnum.ts create mode 100644 src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts create mode 100644 src/modules/objects/services/CreateObjectService.ts diff --git a/src/modules/objects/domain/dtos/ICreateObjectDTO.ts b/src/modules/objects/domain/dtos/ICreateObjectDTO.ts new file mode 100644 index 0000000..7543a64 --- /dev/null +++ b/src/modules/objects/domain/dtos/ICreateObjectDTO.ts @@ -0,0 +1,10 @@ +import { TypeEnum } from '@modules/objects/infra/typeorm/entities/TypeEnum'; + +interface ICreateObjectDTO { + name: string; + comments: string; + type: TypeEnum; + category_id: string; +} + +export { ICreateObjectDTO }; diff --git a/src/modules/objects/domain/models/IObject.ts b/src/modules/objects/domain/models/IObject.ts new file mode 100644 index 0000000..68d7786 --- /dev/null +++ b/src/modules/objects/domain/models/IObject.ts @@ -0,0 +1,16 @@ +import { Category } from '@modules/categories/infra/typeorm/entities/Category'; +import { TypeEnum } from '@modules/objects/infra/typeorm/entities/TypeEnum'; + +interface IObject { + id: string; + name: string; + comments: string; + available: boolean; + type: TypeEnum; + category_id: string; + category: Category; + created_at: Date; + updated_at: Date; +} + +export { IObject }; diff --git a/src/modules/objects/domain/repositories/IObjectsRepository.ts b/src/modules/objects/domain/repositories/IObjectsRepository.ts new file mode 100644 index 0000000..62c54db --- /dev/null +++ b/src/modules/objects/domain/repositories/IObjectsRepository.ts @@ -0,0 +1,8 @@ +import { ICreateObjectDTO } from '../dtos/ICreateObjectDTO'; +import { IObject } from '../models/IObject'; + +interface IObjectsRepository { + create(data: ICreateObjectDTO): Promise; +} + +export { IObjectsRepository }; diff --git a/src/modules/objects/infra/http/controllers/CreateObjectController.ts b/src/modules/objects/infra/http/controllers/CreateObjectController.ts new file mode 100644 index 0000000..24e54f0 --- /dev/null +++ b/src/modules/objects/infra/http/controllers/CreateObjectController.ts @@ -0,0 +1,22 @@ +import { CreateObjectService } from '@modules/objects/services/CreateObjectService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class CreateObjectController { + async handle(request: Request, response: Response): Promise { + const { name, comments, type, category_id } = request.body; + + const createObjectService = container.resolve(CreateObjectService); + + const createObject = await createObjectService.execute({ + name, + comments, + type, + category_id, + }); + + return response.status(201).json(createObject); + } +} + +export { CreateObjectController }; diff --git a/src/modules/objects/infra/http/routes/objects.routes.ts b/src/modules/objects/infra/http/routes/objects.routes.ts new file mode 100644 index 0000000..ee7ec54 --- /dev/null +++ b/src/modules/objects/infra/http/routes/objects.routes.ts @@ -0,0 +1,11 @@ +import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; +import { Router } from 'express'; +import { CreateObjectController } from '../controllers/CreateObjectController'; + +const objectsRoutes = Router(); + +const createObjectController = new CreateObjectController(); + +objectsRoutes.post('/', ensureAuthenticated, createObjectController.handle); + +export { objectsRoutes }; diff --git a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts new file mode 100644 index 0000000..3d6d18d --- /dev/null +++ b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts @@ -0,0 +1,55 @@ +import { Category } from '@modules/categories/infra/typeorm/entities/Category'; +import { IObject } from '@modules/objects/domain/models/IObject'; + +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + PrimaryColumn, + UpdateDateColumn, +} from 'typeorm'; + +import { v4 as uuidV4 } from 'uuid'; +import { TypeEnum } from './TypeEnum'; + +@Entity('objects') +class ObjectLostFound implements IObject { + @PrimaryColumn() + id: string; + + @Column() + name: string; + + @Column() + comments: string; + + @Column() + available: boolean; + + @Column({ type: 'enum', enum: TypeEnum }) + type: TypeEnum; + + @Column() + category_id: string; + + @ManyToOne(() => Category) + @JoinColumn({ name: 'category_id' }) + category: Category; + + @CreateDateColumn() + created_at: Date; + + @UpdateDateColumn() + updated_at: Date; + + constructor() { + if (!this.id) { + this.id = uuidV4(); + this.available = true; + } + } +} + +export { ObjectLostFound }; diff --git a/src/modules/objects/infra/typeorm/entities/TypeEnum.ts b/src/modules/objects/infra/typeorm/entities/TypeEnum.ts new file mode 100644 index 0000000..3e46533 --- /dev/null +++ b/src/modules/objects/infra/typeorm/entities/TypeEnum.ts @@ -0,0 +1,4 @@ +export enum TypeEnum { + Found = 'Perdido', + Lost = 'Achado', +} diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts new file mode 100644 index 0000000..17f18f5 --- /dev/null +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts @@ -0,0 +1,33 @@ +import { ICreateObjectDTO } from '@modules/objects/domain/dtos/ICreateObjectDTO'; +import { IObject } from '@modules/objects/domain/models/IObject'; +import { IObjectsRepository } from '@modules/objects/domain/repositories/IObjectsRepository'; +import { getRepository, Repository } from 'typeorm'; +import { ObjectLostFound } from '../entities/ObjectLostFound'; + +class ObjectsRepository implements IObjectsRepository { + private repository: Repository; + + constructor() { + this.repository = getRepository(ObjectLostFound); + } + + async create({ + name, + comments, + type, + category_id, + }: ICreateObjectDTO): Promise { + const object = this.repository.create({ + name, + comments, + type, + category_id, + }); + + await this.repository.save(object); + + return object; + } +} + +export { ObjectsRepository }; diff --git a/src/modules/objects/services/CreateObjectService.ts b/src/modules/objects/services/CreateObjectService.ts new file mode 100644 index 0000000..d64e5df --- /dev/null +++ b/src/modules/objects/services/CreateObjectService.ts @@ -0,0 +1,30 @@ +import { inject, injectable } from 'tsyringe'; +import { ICreateObjectDTO } from '../domain/dtos/ICreateObjectDTO'; +import { IObject } from '../domain/models/IObject'; +import { IObjectsRepository } from '../domain/repositories/IObjectsRepository'; + +@injectable() +class CreateObjectService { + constructor( + @inject('ObjectsRepository') + private objectsRepository: IObjectsRepository, + ) {} + + async execute({ + name, + comments, + type, + category_id, + }: ICreateObjectDTO): Promise { + const object = this.objectsRepository.create({ + name, + comments, + type, + category_id, + }); + + return object; + } +} + +export { CreateObjectService }; diff --git a/src/shared/container/index.ts b/src/shared/container/index.ts index a59260c..5b4a51f 100644 --- a/src/shared/container/index.ts +++ b/src/shared/container/index.ts @@ -8,6 +8,8 @@ import { UserTokensRepository } from '@modules/users/infra/typeorm/repositories/ import { IUserTokensRepository } from '@modules/users/domain/repositories/IUsersTokensRepository'; import { ICategoriesRepository } from '@modules/categories/domain/repositories/ICategoriesRepository'; import { CategoriesRepository } from '@modules/categories/infra/typeorm/repositories/CategoriesRepository'; +import { IObjectsRepository } from '@modules/objects/domain/repositories/IObjectsRepository'; +import { ObjectsRepository } from '@modules/objects/infra/typeorm/repositories/ObjectsRepository'; container.registerSingleton( 'UsersRepository', @@ -23,3 +25,8 @@ container.registerSingleton( 'CategoriesRepository', CategoriesRepository, ); + +container.registerSingleton( + 'ObjectsRepository', + ObjectsRepository, +); diff --git a/src/shared/infra/http/routes/index.ts b/src/shared/infra/http/routes/index.ts index 8ce95ee..9c78e3c 100644 --- a/src/shared/infra/http/routes/index.ts +++ b/src/shared/infra/http/routes/index.ts @@ -1,4 +1,5 @@ import { categoriesRoutes } from '@modules/categories/infra/http/routes/categories.routes'; +import { objectsRoutes } from '@modules/objects/infra/http/routes/objects.routes'; import { adminRoutes } from '@modules/users/infra/http/routes/admin.routes'; import { passwordRoutes } from '@modules/users/infra/http/routes/password.routes'; import { profileRoutes } from '@modules/users/infra/http/routes/profile.routes'; @@ -13,6 +14,7 @@ routes.use('/admin', adminRoutes); routes.use('/profile', profileRoutes); routes.use('/password', passwordRoutes); routes.use('/categories', categoriesRoutes); +routes.use('/objects', objectsRoutes); routes.use(sessionsRoutes); export { routes }; From 4d88fc45222d528ed566a1a40dd3b8f6e647892c Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 22:59:51 -0300 Subject: [PATCH 51/92] feat: create display a user --- .../http/controllers/ShowUserController.ts | 17 +++++++++++ .../users/infra/http/routes/users.routes.ts | 10 +++++++ src/modules/users/services/ShowUserService.ts | 28 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 src/modules/users/infra/http/controllers/ShowUserController.ts create mode 100644 src/modules/users/services/ShowUserService.ts diff --git a/src/modules/users/infra/http/controllers/ShowUserController.ts b/src/modules/users/infra/http/controllers/ShowUserController.ts new file mode 100644 index 0000000..6299d1c --- /dev/null +++ b/src/modules/users/infra/http/controllers/ShowUserController.ts @@ -0,0 +1,17 @@ +import { ShowUserService } from '@modules/users/services/ShowUserService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class ShowUserController { + async handle(request: Request, response: Response): Promise { + const { id } = request.params; + + const showUserService = container.resolve(ShowUserService); + + const user = await showUserService.execute({ id }); + + return response.json(user); + } +} + +export { ShowUserController }; diff --git a/src/modules/users/infra/http/routes/users.routes.ts b/src/modules/users/infra/http/routes/users.routes.ts index 0b7a0eb..1c3688f 100644 --- a/src/modules/users/infra/http/routes/users.routes.ts +++ b/src/modules/users/infra/http/routes/users.routes.ts @@ -5,14 +5,24 @@ import uploadConfig from '@config/upload'; import multer from 'multer'; import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; import { UpdateAvatarUserController } from '../controllers/UpdateAvatarUserController'; +import ensureAdmin from '@shared/infra/http/middlewares/ensureAdmin'; +import { ShowUserController } from '../controllers/ShowUserController'; const usersRoutes = Router(); const createUserController = new CreateUserController(); const updateAvatarUserController = new UpdateAvatarUserController(); +const showUserController = new ShowUserController(); const upload = multer(uploadConfig); +usersRoutes.get( + '/:id', + ensureAuthenticated, + ensureAdmin, + showUserController.handle, +); + usersRoutes.post( '/', celebrate({ diff --git a/src/modules/users/services/ShowUserService.ts b/src/modules/users/services/ShowUserService.ts new file mode 100644 index 0000000..52968c8 --- /dev/null +++ b/src/modules/users/services/ShowUserService.ts @@ -0,0 +1,28 @@ +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { IUser } from '../domain/models/IUser'; +import { IUsersRepository } from '../domain/repositories/IUsersRepository'; + +interface IRequest { + id: string; +} + +@injectable() +class ShowUserService { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + ) {} + + async execute({ id }: IRequest): Promise { + const user = await this.usersRepository.findById(id); + + if (!user) { + throw new AppError('User not found', 404); + } + + return user; + } +} + +export { ShowUserService }; From 2d602577cf48ef65ff1f5426a9b94a5326518b15 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Thu, 20 Jan 2022 23:23:58 -0300 Subject: [PATCH 52/92] feat: list all objects --- .../domain/repositories/IObjectsRepository.ts | 1 + .../controllers/ListAllObjectsController.ts | 15 +++++++++++++++ .../infra/http/routes/objects.routes.ts | 4 ++++ .../typeorm/repositories/ObjectsRepository.ts | 6 ++++++ .../objects/services/ListAllObjectsService.ts | 19 +++++++++++++++++++ 5 files changed, 45 insertions(+) create mode 100644 src/modules/objects/infra/http/controllers/ListAllObjectsController.ts create mode 100644 src/modules/objects/services/ListAllObjectsService.ts diff --git a/src/modules/objects/domain/repositories/IObjectsRepository.ts b/src/modules/objects/domain/repositories/IObjectsRepository.ts index 62c54db..ee4addb 100644 --- a/src/modules/objects/domain/repositories/IObjectsRepository.ts +++ b/src/modules/objects/domain/repositories/IObjectsRepository.ts @@ -3,6 +3,7 @@ import { IObject } from '../models/IObject'; interface IObjectsRepository { create(data: ICreateObjectDTO): Promise; + findAll(): Promise; } export { IObjectsRepository }; diff --git a/src/modules/objects/infra/http/controllers/ListAllObjectsController.ts b/src/modules/objects/infra/http/controllers/ListAllObjectsController.ts new file mode 100644 index 0000000..bdc667e --- /dev/null +++ b/src/modules/objects/infra/http/controllers/ListAllObjectsController.ts @@ -0,0 +1,15 @@ +import { ListAllObjectsService } from '@modules/objects/services/ListAllObjectsService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class ListAllObjectsController { + async handle(request: Request, response: Response): Promise { + const listAllObjectsService = container.resolve(ListAllObjectsService); + + const objects = await listAllObjectsService.execute(); + + return response.json(objects); + } +} + +export { ListAllObjectsController }; diff --git a/src/modules/objects/infra/http/routes/objects.routes.ts b/src/modules/objects/infra/http/routes/objects.routes.ts index ee7ec54..73b9b4f 100644 --- a/src/modules/objects/infra/http/routes/objects.routes.ts +++ b/src/modules/objects/infra/http/routes/objects.routes.ts @@ -1,11 +1,15 @@ import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; import { Router } from 'express'; import { CreateObjectController } from '../controllers/CreateObjectController'; +import { ListAllObjectsController } from '../controllers/ListAllObjectsController'; const objectsRoutes = Router(); const createObjectController = new CreateObjectController(); +const listAllObjectsController = new ListAllObjectsController(); objectsRoutes.post('/', ensureAuthenticated, createObjectController.handle); +objectsRoutes.get('/', listAllObjectsController.handle); + export { objectsRoutes }; diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts index 17f18f5..77eae96 100644 --- a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts @@ -11,6 +11,12 @@ class ObjectsRepository implements IObjectsRepository { this.repository = getRepository(ObjectLostFound); } + async findAll(): Promise { + const objects = await this.repository.find(); + + return objects; + } + async create({ name, comments, diff --git a/src/modules/objects/services/ListAllObjectsService.ts b/src/modules/objects/services/ListAllObjectsService.ts new file mode 100644 index 0000000..4518363 --- /dev/null +++ b/src/modules/objects/services/ListAllObjectsService.ts @@ -0,0 +1,19 @@ +import { inject, injectable } from 'tsyringe'; +import { IObject } from '../domain/models/IObject'; +import { IObjectsRepository } from '../domain/repositories/IObjectsRepository'; + +@injectable() +class ListAllObjectsService { + constructor( + @inject('ObjectsRepository') + private objectsRepository: IObjectsRepository, + ) {} + + async execute(): Promise { + const objects = await this.objectsRepository.findAll(); + + return objects; + } +} + +export { ListAllObjectsService }; From 9ad32e84221b2dc2ffd1c02be53778979dafd7a5 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 00:38:12 -0300 Subject: [PATCH 53/92] refactor: adding user id of objects --- src/modules/objects/domain/dtos/ICreateObjectDTO.ts | 1 + src/modules/objects/domain/models/IObject.ts | 1 + .../infra/http/controllers/CreateObjectController.ts | 2 ++ .../infra/typeorm/entities/ObjectLostFound.ts | 3 +++ .../infra/typeorm/repositories/ObjectsRepository.ts | 2 ++ src/modules/objects/services/CreateObjectService.ts | 2 ++ .../typeorm/migrations/1642708699976-CreateObject.ts | 12 ++++++++++++ 7 files changed, 23 insertions(+) diff --git a/src/modules/objects/domain/dtos/ICreateObjectDTO.ts b/src/modules/objects/domain/dtos/ICreateObjectDTO.ts index 7543a64..825ef41 100644 --- a/src/modules/objects/domain/dtos/ICreateObjectDTO.ts +++ b/src/modules/objects/domain/dtos/ICreateObjectDTO.ts @@ -5,6 +5,7 @@ interface ICreateObjectDTO { comments: string; type: TypeEnum; category_id: string; + user_id: string; } export { ICreateObjectDTO }; diff --git a/src/modules/objects/domain/models/IObject.ts b/src/modules/objects/domain/models/IObject.ts index 68d7786..b8aa304 100644 --- a/src/modules/objects/domain/models/IObject.ts +++ b/src/modules/objects/domain/models/IObject.ts @@ -7,6 +7,7 @@ interface IObject { comments: string; available: boolean; type: TypeEnum; + user_id: string; category_id: string; category: Category; created_at: Date; diff --git a/src/modules/objects/infra/http/controllers/CreateObjectController.ts b/src/modules/objects/infra/http/controllers/CreateObjectController.ts index 24e54f0..9e5caeb 100644 --- a/src/modules/objects/infra/http/controllers/CreateObjectController.ts +++ b/src/modules/objects/infra/http/controllers/CreateObjectController.ts @@ -5,6 +5,7 @@ import { container } from 'tsyringe'; class CreateObjectController { async handle(request: Request, response: Response): Promise { const { name, comments, type, category_id } = request.body; + const { id } = request.user; const createObjectService = container.resolve(CreateObjectService); @@ -13,6 +14,7 @@ class CreateObjectController { comments, type, category_id, + user_id: id, }); return response.status(201).json(createObject); diff --git a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts index 3d6d18d..86c47b1 100644 --- a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts +++ b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts @@ -31,6 +31,9 @@ class ObjectLostFound implements IObject { @Column({ type: 'enum', enum: TypeEnum }) type: TypeEnum; + @Column() + user_id: string; + @Column() category_id: string; diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts index 77eae96..64ad85f 100644 --- a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts @@ -22,12 +22,14 @@ class ObjectsRepository implements IObjectsRepository { comments, type, category_id, + user_id, }: ICreateObjectDTO): Promise { const object = this.repository.create({ name, comments, type, category_id, + user_id, }); await this.repository.save(object); diff --git a/src/modules/objects/services/CreateObjectService.ts b/src/modules/objects/services/CreateObjectService.ts index d64e5df..8989692 100644 --- a/src/modules/objects/services/CreateObjectService.ts +++ b/src/modules/objects/services/CreateObjectService.ts @@ -15,12 +15,14 @@ class CreateObjectService { comments, type, category_id, + user_id, }: ICreateObjectDTO): Promise { const object = this.objectsRepository.create({ name, comments, type, category_id, + user_id, }); return object; diff --git a/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts b/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts index f4cfc9c..898de1a 100644 --- a/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts +++ b/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts @@ -37,6 +37,10 @@ export class CreateObject1642708699976 implements MigrationInterface { type: 'uuid', isNullable: true, }, + { + name: 'user_id', + type: 'uuid', + }, { name: 'created_at', type: 'timestamp', @@ -57,6 +61,14 @@ export class CreateObject1642708699976 implements MigrationInterface { onDelete: 'SET NULL', onUpdate: 'SET NULL', }, + { + name: 'FKUserObject', + referencedTableName: 'users', + referencedColumnNames: ['id'], + columnNames: ['user_id'], + onDelete: 'SET NULL', + onUpdate: 'SET NULL', + }, ], }), ); From 41158f1a84cb0bbed5fe8ead9de045e5dbfe10ca Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 12:35:26 -0300 Subject: [PATCH 54/92] refactor: object refactoring --- .../objects/domain/dtos/ICreateObjectDTO.ts | 1 - src/modules/objects/domain/models/IObject.ts | 1 - .../controllers/CreateObjectController.ts | 2 -- .../infra/typeorm/entities/ObjectImage.ts | 25 +++++++++++++++++++ .../infra/typeorm/entities/ObjectLostFound.ts | 3 --- .../typeorm/repositories/ObjectsRepository.ts | 2 -- .../objects/services/CreateObjectService.ts | 2 -- .../migrations/1642708699976-CreateObject.ts | 12 --------- 8 files changed, 25 insertions(+), 23 deletions(-) create mode 100644 src/modules/objects/infra/typeorm/entities/ObjectImage.ts diff --git a/src/modules/objects/domain/dtos/ICreateObjectDTO.ts b/src/modules/objects/domain/dtos/ICreateObjectDTO.ts index 825ef41..7543a64 100644 --- a/src/modules/objects/domain/dtos/ICreateObjectDTO.ts +++ b/src/modules/objects/domain/dtos/ICreateObjectDTO.ts @@ -5,7 +5,6 @@ interface ICreateObjectDTO { comments: string; type: TypeEnum; category_id: string; - user_id: string; } export { ICreateObjectDTO }; diff --git a/src/modules/objects/domain/models/IObject.ts b/src/modules/objects/domain/models/IObject.ts index b8aa304..68d7786 100644 --- a/src/modules/objects/domain/models/IObject.ts +++ b/src/modules/objects/domain/models/IObject.ts @@ -7,7 +7,6 @@ interface IObject { comments: string; available: boolean; type: TypeEnum; - user_id: string; category_id: string; category: Category; created_at: Date; diff --git a/src/modules/objects/infra/http/controllers/CreateObjectController.ts b/src/modules/objects/infra/http/controllers/CreateObjectController.ts index 9e5caeb..24e54f0 100644 --- a/src/modules/objects/infra/http/controllers/CreateObjectController.ts +++ b/src/modules/objects/infra/http/controllers/CreateObjectController.ts @@ -5,7 +5,6 @@ import { container } from 'tsyringe'; class CreateObjectController { async handle(request: Request, response: Response): Promise { const { name, comments, type, category_id } = request.body; - const { id } = request.user; const createObjectService = container.resolve(CreateObjectService); @@ -14,7 +13,6 @@ class CreateObjectController { comments, type, category_id, - user_id: id, }); return response.status(201).json(createObject); diff --git a/src/modules/objects/infra/typeorm/entities/ObjectImage.ts b/src/modules/objects/infra/typeorm/entities/ObjectImage.ts new file mode 100644 index 0000000..f2f0314 --- /dev/null +++ b/src/modules/objects/infra/typeorm/entities/ObjectImage.ts @@ -0,0 +1,25 @@ +import { Column, CreateDateColumn, Entity, PrimaryColumn } from 'typeorm'; +import { v4 as uuidV4 } from 'uuid'; + +@Entity('objects_image') +class ObjectImage { + @PrimaryColumn() + id: string; + + @Column() + object_id: string; + + @Column() + image_name: string; + + @CreateDateColumn() + created_at: Date; + + constructor() { + if (!this.id) { + this.id = uuidV4(); + } + } +} + +export { ObjectImage }; diff --git a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts index 86c47b1..3d6d18d 100644 --- a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts +++ b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts @@ -31,9 +31,6 @@ class ObjectLostFound implements IObject { @Column({ type: 'enum', enum: TypeEnum }) type: TypeEnum; - @Column() - user_id: string; - @Column() category_id: string; diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts index 64ad85f..77eae96 100644 --- a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts @@ -22,14 +22,12 @@ class ObjectsRepository implements IObjectsRepository { comments, type, category_id, - user_id, }: ICreateObjectDTO): Promise { const object = this.repository.create({ name, comments, type, category_id, - user_id, }); await this.repository.save(object); diff --git a/src/modules/objects/services/CreateObjectService.ts b/src/modules/objects/services/CreateObjectService.ts index 8989692..d64e5df 100644 --- a/src/modules/objects/services/CreateObjectService.ts +++ b/src/modules/objects/services/CreateObjectService.ts @@ -15,14 +15,12 @@ class CreateObjectService { comments, type, category_id, - user_id, }: ICreateObjectDTO): Promise { const object = this.objectsRepository.create({ name, comments, type, category_id, - user_id, }); return object; diff --git a/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts b/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts index 898de1a..f4cfc9c 100644 --- a/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts +++ b/src/shared/infra/typeorm/migrations/1642708699976-CreateObject.ts @@ -37,10 +37,6 @@ export class CreateObject1642708699976 implements MigrationInterface { type: 'uuid', isNullable: true, }, - { - name: 'user_id', - type: 'uuid', - }, { name: 'created_at', type: 'timestamp', @@ -61,14 +57,6 @@ export class CreateObject1642708699976 implements MigrationInterface { onDelete: 'SET NULL', onUpdate: 'SET NULL', }, - { - name: 'FKUserObject', - referencedTableName: 'users', - referencedColumnNames: ['id'], - columnNames: ['user_id'], - onDelete: 'SET NULL', - onUpdate: 'SET NULL', - }, ], }), ); From 16e98305ccbe02fbf515257ad914a2c6289cacf6 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 12:35:57 -0300 Subject: [PATCH 55/92] chore: adding migration object images --- .../1642777659560-CreateObejectImages.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/shared/infra/typeorm/migrations/1642777659560-CreateObejectImages.ts diff --git a/src/shared/infra/typeorm/migrations/1642777659560-CreateObejectImages.ts b/src/shared/infra/typeorm/migrations/1642777659560-CreateObejectImages.ts new file mode 100644 index 0000000..92c0bbd --- /dev/null +++ b/src/shared/infra/typeorm/migrations/1642777659560-CreateObejectImages.ts @@ -0,0 +1,50 @@ +import { MigrationInterface, QueryRunner, Table } from 'typeorm'; + +export class CreateObejectImages1642777659560 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: 'objects_image', + columns: [ + { + name: 'id', + type: 'uuid', + isPrimary: true, + }, + { + name: 'object_id', + type: 'uuid', + }, + { + name: 'image_name', + type: 'varchar', + }, + { + name: 'created_at', + type: 'timestamp', + default: 'now()', + }, + { + name: 'updated_at', + type: 'timestamp', + default: 'now()', + }, + ], + foreignKeys: [ + { + name: 'FKObjectImage', + referencedTableName: 'objects', + referencedColumnNames: ['id'], + columnNames: ['object_id'], + onDelete: 'SET NULL', + onUpdate: 'SET NULL', + }, + ], + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable('objects_image'); + } +} From 92d31280290b555d91a28b212f6c79aadeba21e3 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 13:57:30 -0300 Subject: [PATCH 56/92] feat: create upload images object --- .../objects/domain/models/IObjectImage.ts | 9 ++++++ .../repositories/IObjectsImagesRepository.ts | 7 +++++ .../UploadObjectImageController.ts | 29 +++++++++++++++++++ .../infra/http/routes/objects.routes.ts | 13 +++++++++ .../infra/typeorm/entities/ObjectImage.ts | 6 +++- .../repositories/ObjectsImagesRepository.ts | 25 ++++++++++++++++ .../services/UploadObjectImageService.ts | 23 +++++++++++++++ src/shared/container/index.ts | 7 +++++ 8 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/modules/objects/domain/models/IObjectImage.ts create mode 100644 src/modules/objects/domain/repositories/IObjectsImagesRepository.ts create mode 100644 src/modules/objects/infra/http/controllers/UploadObjectImageController.ts create mode 100644 src/modules/objects/infra/typeorm/repositories/ObjectsImagesRepository.ts create mode 100644 src/modules/objects/services/UploadObjectImageService.ts diff --git a/src/modules/objects/domain/models/IObjectImage.ts b/src/modules/objects/domain/models/IObjectImage.ts new file mode 100644 index 0000000..85878ac --- /dev/null +++ b/src/modules/objects/domain/models/IObjectImage.ts @@ -0,0 +1,9 @@ +interface IObjectImage { + id: string; + object_id: string; + image_name: string; + created_at: Date; + updated_at: Date; +} + +export { IObjectImage }; diff --git a/src/modules/objects/domain/repositories/IObjectsImagesRepository.ts b/src/modules/objects/domain/repositories/IObjectsImagesRepository.ts new file mode 100644 index 0000000..dc0b7bc --- /dev/null +++ b/src/modules/objects/domain/repositories/IObjectsImagesRepository.ts @@ -0,0 +1,7 @@ +import { IObjectImage } from '../models/IObjectImage'; + +interface IObjectsImagesRepository { + create(object_id: string, image_name: string): Promise; +} + +export { IObjectsImagesRepository }; diff --git a/src/modules/objects/infra/http/controllers/UploadObjectImageController.ts b/src/modules/objects/infra/http/controllers/UploadObjectImageController.ts new file mode 100644 index 0000000..957f000 --- /dev/null +++ b/src/modules/objects/infra/http/controllers/UploadObjectImageController.ts @@ -0,0 +1,29 @@ +import { UploadObjectImageService } from '@modules/objects/services/UploadObjectImageService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +interface IFiles { + filename: string; +} + +class UploadObjectImageController { + async handle(request: Request, response: Response): Promise { + const { id } = request.params; + const images = request.files as IFiles[]; + + const uploadObjectImageService = container.resolve( + UploadObjectImageService, + ); + + const images_name = images.map(file => file.filename); + + await uploadObjectImageService.execute({ + object_id: id, + images_name, + }); + + return response.status(201).send(); + } +} + +export { UploadObjectImageController }; diff --git a/src/modules/objects/infra/http/routes/objects.routes.ts b/src/modules/objects/infra/http/routes/objects.routes.ts index 73b9b4f..92d5520 100644 --- a/src/modules/objects/infra/http/routes/objects.routes.ts +++ b/src/modules/objects/infra/http/routes/objects.routes.ts @@ -1,15 +1,28 @@ import ensureAuthenticated from '@shared/infra/http/middlewares/ensureAuthenticated'; import { Router } from 'express'; +import multer from 'multer'; import { CreateObjectController } from '../controllers/CreateObjectController'; import { ListAllObjectsController } from '../controllers/ListAllObjectsController'; +import { UploadObjectImageController } from '../controllers/UploadObjectImageController'; +import uploadConfig from '@config/upload'; const objectsRoutes = Router(); const createObjectController = new CreateObjectController(); const listAllObjectsController = new ListAllObjectsController(); +const uploadObjectImageController = new UploadObjectImageController(); + +const uploadImages = multer(uploadConfig); objectsRoutes.post('/', ensureAuthenticated, createObjectController.handle); objectsRoutes.get('/', listAllObjectsController.handle); +objectsRoutes.post( + '/images/:id', + ensureAuthenticated, + uploadImages.array('images'), + uploadObjectImageController.handle, +); + export { objectsRoutes }; diff --git a/src/modules/objects/infra/typeorm/entities/ObjectImage.ts b/src/modules/objects/infra/typeorm/entities/ObjectImage.ts index f2f0314..dd77200 100644 --- a/src/modules/objects/infra/typeorm/entities/ObjectImage.ts +++ b/src/modules/objects/infra/typeorm/entities/ObjectImage.ts @@ -1,8 +1,9 @@ +import { IObjectImage } from '@modules/objects/domain/models/IObjectImage'; import { Column, CreateDateColumn, Entity, PrimaryColumn } from 'typeorm'; import { v4 as uuidV4 } from 'uuid'; @Entity('objects_image') -class ObjectImage { +class ObjectImage implements IObjectImage { @PrimaryColumn() id: string; @@ -15,6 +16,9 @@ class ObjectImage { @CreateDateColumn() created_at: Date; + @CreateDateColumn() + updated_at: Date; + constructor() { if (!this.id) { this.id = uuidV4(); diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsImagesRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsImagesRepository.ts new file mode 100644 index 0000000..d39e893 --- /dev/null +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsImagesRepository.ts @@ -0,0 +1,25 @@ +import { IObjectImage } from '@modules/objects/domain/models/IObjectImage'; +import { IObjectsImagesRepository } from '@modules/objects/domain/repositories/IObjectsImagesRepository'; +import { getRepository, Repository } from 'typeorm'; +import { ObjectImage } from '../entities/ObjectImage'; + +class ObjectsImagesRepository implements IObjectsImagesRepository { + private repository: Repository; + + constructor() { + this.repository = getRepository(ObjectImage); + } + + async create(object_id: string, image_name: string): Promise { + const objectImage = this.repository.create({ + object_id, + image_name, + }); + + await this.repository.save(objectImage); + + return objectImage; + } +} + +export { ObjectsImagesRepository }; diff --git a/src/modules/objects/services/UploadObjectImageService.ts b/src/modules/objects/services/UploadObjectImageService.ts new file mode 100644 index 0000000..e8e6680 --- /dev/null +++ b/src/modules/objects/services/UploadObjectImageService.ts @@ -0,0 +1,23 @@ +import { inject, injectable } from 'tsyringe'; +import { IObjectsImagesRepository } from '../domain/repositories/IObjectsImagesRepository'; + +interface IRequest { + object_id: string; + images_name: string[]; +} + +@injectable() +class UploadObjectImageService { + constructor( + @inject('ObjectsImagesRepository') + private objectsImagesRepository: IObjectsImagesRepository, + ) {} + + async execute({ object_id, images_name }: IRequest): Promise { + images_name.map(async image => { + await this.objectsImagesRepository.create(object_id, image); + }); + } +} + +export { UploadObjectImageService }; diff --git a/src/shared/container/index.ts b/src/shared/container/index.ts index 5b4a51f..8c333fc 100644 --- a/src/shared/container/index.ts +++ b/src/shared/container/index.ts @@ -10,6 +10,8 @@ import { ICategoriesRepository } from '@modules/categories/domain/repositories/I import { CategoriesRepository } from '@modules/categories/infra/typeorm/repositories/CategoriesRepository'; import { IObjectsRepository } from '@modules/objects/domain/repositories/IObjectsRepository'; import { ObjectsRepository } from '@modules/objects/infra/typeorm/repositories/ObjectsRepository'; +import { IObjectsImagesRepository } from '@modules/objects/domain/repositories/IObjectsImagesRepository'; +import { ObjectsImagesRepository } from '@modules/objects/infra/typeorm/repositories/ObjectsImagesRepository'; container.registerSingleton( 'UsersRepository', @@ -30,3 +32,8 @@ container.registerSingleton( 'ObjectsRepository', ObjectsRepository, ); + +container.registerSingleton( + 'ObjectsImagesRepository', + ObjectsImagesRepository, +); From 74a0baab5c3fb4d09fa118b4e9b12fd256670bf3 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 15:21:11 -0300 Subject: [PATCH 57/92] feat: listing objects by filter --- .../domain/repositories/IObjectsRepository.ts | 1 + .../ListAvaliableObjectController.ts | 23 ++++++++++++++++ .../infra/http/routes/objects.routes.ts | 4 +++ .../typeorm/repositories/ObjectsRepository.ts | 18 +++++++++++++ .../services/ListAvaliableObjectService.ts | 27 +++++++++++++++++++ 5 files changed, 73 insertions(+) create mode 100644 src/modules/objects/infra/http/controllers/ListAvaliableObjectController.ts create mode 100644 src/modules/objects/services/ListAvaliableObjectService.ts diff --git a/src/modules/objects/domain/repositories/IObjectsRepository.ts b/src/modules/objects/domain/repositories/IObjectsRepository.ts index ee4addb..d36aab0 100644 --- a/src/modules/objects/domain/repositories/IObjectsRepository.ts +++ b/src/modules/objects/domain/repositories/IObjectsRepository.ts @@ -4,6 +4,7 @@ import { IObject } from '../models/IObject'; interface IObjectsRepository { create(data: ICreateObjectDTO): Promise; findAll(): Promise; + findAvaliable(name?: string, category_id?: string): Promise; } export { IObjectsRepository }; diff --git a/src/modules/objects/infra/http/controllers/ListAvaliableObjectController.ts b/src/modules/objects/infra/http/controllers/ListAvaliableObjectController.ts new file mode 100644 index 0000000..a92a554 --- /dev/null +++ b/src/modules/objects/infra/http/controllers/ListAvaliableObjectController.ts @@ -0,0 +1,23 @@ +import { ListAvaliableObjectService } from '@modules/objects/services/ListAvaliableObjectService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class ListAvaliableObjectController { + async handle(request: Request, response: Response): Promise { + const { name, category_id } = request.query; + + const listAvaliableObjectService = container.resolve( + ListAvaliableObjectService, + ); + + const allAvailablesObjects = await listAvaliableObjectService.execute({ + name: name as string, + + category_id: category_id as string, + }); + + return response.json(allAvailablesObjects); + } +} + +export { ListAvaliableObjectController }; diff --git a/src/modules/objects/infra/http/routes/objects.routes.ts b/src/modules/objects/infra/http/routes/objects.routes.ts index 92d5520..8dab443 100644 --- a/src/modules/objects/infra/http/routes/objects.routes.ts +++ b/src/modules/objects/infra/http/routes/objects.routes.ts @@ -5,12 +5,14 @@ import { CreateObjectController } from '../controllers/CreateObjectController'; import { ListAllObjectsController } from '../controllers/ListAllObjectsController'; import { UploadObjectImageController } from '../controllers/UploadObjectImageController'; import uploadConfig from '@config/upload'; +import { ListAvaliableObjectController } from '../controllers/ListAvaliableObjectController'; const objectsRoutes = Router(); const createObjectController = new CreateObjectController(); const listAllObjectsController = new ListAllObjectsController(); const uploadObjectImageController = new UploadObjectImageController(); +const listAvaliableObjectController = new ListAvaliableObjectController(); const uploadImages = multer(uploadConfig); @@ -18,6 +20,8 @@ objectsRoutes.post('/', ensureAuthenticated, createObjectController.handle); objectsRoutes.get('/', listAllObjectsController.handle); +objectsRoutes.get('/available', listAvaliableObjectController.handle); + objectsRoutes.post( '/images/:id', ensureAuthenticated, diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts index 77eae96..3189d11 100644 --- a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts @@ -11,6 +11,24 @@ class ObjectsRepository implements IObjectsRepository { this.repository = getRepository(ObjectLostFound); } + async findAvaliable(name?: string, category_id?: string): Promise { + const objectsQuery = await this.repository + .createQueryBuilder('c') + .where('available = :available', { available: true }); + + if (name) { + objectsQuery.andWhere('name = :name', { name }); + } + + if (category_id) { + objectsQuery.andWhere('category_id = :category_id', { category_id }); + } + + const objects = await objectsQuery.getMany(); + + return objects; + } + async findAll(): Promise { const objects = await this.repository.find(); diff --git a/src/modules/objects/services/ListAvaliableObjectService.ts b/src/modules/objects/services/ListAvaliableObjectService.ts new file mode 100644 index 0000000..321b535 --- /dev/null +++ b/src/modules/objects/services/ListAvaliableObjectService.ts @@ -0,0 +1,27 @@ +import { inject, injectable } from 'tsyringe'; +import { IObject } from '../domain/models/IObject'; +import { IObjectsRepository } from '../domain/repositories/IObjectsRepository'; + +interface IRequest { + name?: string; + category_id?: string; +} + +@injectable() +class ListAvaliableObjectService { + constructor( + @inject('ObjectsRepository') + private objectsRepository: IObjectsRepository, + ) {} + + async execute({ name, category_id }: IRequest): Promise { + const objects = await this.objectsRepository.findAvaliable( + name, + category_id, + ); + + return objects; + } +} + +export { ListAvaliableObjectService }; From 289d7fab2003d929b7ffe2aa49e4629298ba1efe Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 15:32:02 -0300 Subject: [PATCH 58/92] chore: validation created objects --- .../objects/infra/http/routes/objects.routes.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/modules/objects/infra/http/routes/objects.routes.ts b/src/modules/objects/infra/http/routes/objects.routes.ts index 8dab443..40b1a61 100644 --- a/src/modules/objects/infra/http/routes/objects.routes.ts +++ b/src/modules/objects/infra/http/routes/objects.routes.ts @@ -6,6 +6,7 @@ import { ListAllObjectsController } from '../controllers/ListAllObjectsControlle import { UploadObjectImageController } from '../controllers/UploadObjectImageController'; import uploadConfig from '@config/upload'; import { ListAvaliableObjectController } from '../controllers/ListAvaliableObjectController'; +import { celebrate, Joi, Segments } from 'celebrate'; const objectsRoutes = Router(); @@ -16,7 +17,19 @@ const listAvaliableObjectController = new ListAvaliableObjectController(); const uploadImages = multer(uploadConfig); -objectsRoutes.post('/', ensureAuthenticated, createObjectController.handle); +objectsRoutes.post( + '/', + celebrate({ + [Segments.BODY]: { + name: Joi.string().required(), + comments: Joi.string(), + type: Joi.string().required(), + category_id: Joi.string().required().uuid(), + }, + }), + ensureAuthenticated, + createObjectController.handle, +); objectsRoutes.get('/', listAllObjectsController.handle); From 4d0f410f39795af07e78f2d4802b3fc30174de14 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 17:33:21 -0300 Subject: [PATCH 59/92] chore: adding jest --- jest.config.ts | 191 +++++ package.json | 6 +- yarn.lock | 2078 ++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 2226 insertions(+), 49 deletions(-) create mode 100644 jest.config.ts diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..567a93d --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,191 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/configuration + */ + +export default { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + bail: true, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/tmp/jest_rs", + + // Automatically clear mock calls, instances and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + // coverageDirectory: undefined, + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'v8', + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + preset: 'ts-jest', + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + // testEnvironment: "jest-environment-node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + testMatch: ['**/*.spec.ts'], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href + // testURL: "http://localhost", + + // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" + // timers: "real", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; diff --git a/package.json b/package.json index 210950f..d1def42 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,14 @@ "typeorm": "ts-node-dev -r tsconfig-paths/register ./node_modules/typeorm/cli", "lint": "eslint . --ext .ts", "lint-fix": "eslint . --ext .ts --fix", - "seed:admin": "ts-node-dev -r tsconfig-paths/register src/shared/infra/typeorm/seed/admin.ts" + "seed:admin": "ts-node-dev -r tsconfig-paths/register src/shared/infra/typeorm/seed/admin.ts", + "test": "jest" }, "devDependencies": { "@types/bcrypt": "^5.0.0", "@types/cors": "^2.8.12", "@types/express": "^4.17.13", + "@types/jest": "^27.4.0", "@types/joi": "^17.2.3", "@types/jsonwebtoken": "^8.5.8", "@types/multer": "^1.4.7", @@ -25,7 +27,9 @@ "eslint": "^8.7.0", "eslint-config-prettier": "6.15.0", "eslint-plugin-prettier": "3.2.0", + "jest": "^27.4.7", "prettier": "^2.5.1", + "ts-jest": "^27.1.3", "ts-node-dev": "^1.1.8", "tsconfig-paths": "^3.12.0", "typescript": "^4.5.4" diff --git a/yarn.lock b/yarn.lock index 96ba5b1..1be59a5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,290 @@ # yarn lockfile v1 +"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.16.4": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60" + integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q== + +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.10.tgz#ebd034f8e7ac2b6bfcdaa83a161141a646f74b50" + integrity sha512-pbiIdZbCiMx/MM6toR+OfXarYix3uz0oVsnNtfdAGTcCTu3w/JGF8JhirevXLBJUu0WguSZI12qpKnx7EeMyLA== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.16.7" + "@babel/parser" "^7.16.10" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.10" + "@babel/types" "^7.16.8" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.16.8", "@babel/generator@^7.7.2": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe" + integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw== + dependencies: + "@babel/types" "^7.16.8" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-compilation-targets@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" + integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== + dependencies: + "@babel/compat-data" "^7.16.4" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-transforms@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" + integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@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.16.7", "@babel/helper-plugin-utils@^7.8.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + +"@babel/helper-simple-access@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" + integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helpers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc" + integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.10", "@babel/parser@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.10.tgz#aba1b1cb9696a24a19f59c41af9cf17d1c716a88" + integrity sha512-Sm/S9Or6nN8uiFsQU1yodyDW3MWXQhFeqzMPM+t8MJjM+pLsnFVxFZzkpXKvUXh+Gz9cbMoYYs484+Jw/NTEFQ== + +"@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-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.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/template@^7.16.7", "@babel/template@^7.3.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.16.10", "@babel/traverse@^7.16.7", "@babel/traverse@^7.7.2": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.10.tgz#448f940defbe95b5a8029975b051f75993e8239f" + integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.8" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.16.10" + "@babel/types" "^7.16.8" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" + integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + 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== + "@eslint/eslintrc@^1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.0.5.tgz#33f1b838dbf1f923bfa517e008362b78ddbbf318" @@ -43,6 +327,191 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@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@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.4.6.tgz#0742e6787f682b22bdad56f9db2a8a77f6a86107" + integrity sha512-jauXyacQD33n47A44KrlOVeiXHEXDqapSdfb9kTekOchH/Pd18kBIO1+xxJQRLuG+LUuljFCwTG92ra4NW7SpA== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.4.6" + jest-util "^27.4.2" + slash "^3.0.0" + +"@jest/core@^27.4.7": + version "27.4.7" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.4.7.tgz#84eabdf42a25f1fa138272ed229bcf0a1b5e6913" + integrity sha512-n181PurSJkVMS+kClIFSX/LLvw9ExSb+4IMtD6YnfxZVerw9ANYtW0bPrm0MJu2pfe9SY9FJ9FtQ+MdZkrZwjg== + dependencies: + "@jest/console" "^27.4.6" + "@jest/reporters" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^27.4.2" + jest-config "^27.4.7" + jest-haste-map "^27.4.6" + jest-message-util "^27.4.6" + jest-regex-util "^27.4.0" + jest-resolve "^27.4.6" + jest-resolve-dependencies "^27.4.6" + jest-runner "^27.4.6" + jest-runtime "^27.4.6" + jest-snapshot "^27.4.6" + jest-util "^27.4.2" + jest-validate "^27.4.6" + jest-watcher "^27.4.6" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.4.6.tgz#1e92885d64f48c8454df35ed9779fbcf31c56d8b" + integrity sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg== + dependencies: + "@jest/fake-timers" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-mock "^27.4.6" + +"@jest/fake-timers@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.4.6.tgz#e026ae1671316dbd04a56945be2fa251204324e8" + integrity sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A== + dependencies: + "@jest/types" "^27.4.2" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.4.6" + jest-mock "^27.4.6" + jest-util "^27.4.2" + +"@jest/globals@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.4.6.tgz#3f09bed64b0fd7f5f996920258bd4be8f52f060a" + integrity sha512-kAiwMGZ7UxrgPzu8Yv9uvWmXXxsy0GciNejlHvfPIfWkSxChzv6bgTS3YqBkGuHcis+ouMFI2696n2t+XYIeFw== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/types" "^27.4.2" + expect "^27.4.6" + +"@jest/reporters@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.4.6.tgz#b53dec3a93baf9b00826abf95b932de919d6d8dd" + integrity sha512-+Zo9gV81R14+PSq4wzee4GC2mhAN9i9a7qgJWL90Gpx7fHYkWpTBvwWNZUXvJByYR9tAVBdc8VxDWqfJyIUrIQ== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-haste-map "^27.4.6" + jest-resolve "^27.4.6" + jest-util "^27.4.2" + jest-worker "^27.4.6" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + +"@jest/source-map@^27.4.0": + version "27.4.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.4.0.tgz#2f0385d0d884fb3e2554e8f71f8fa957af9a74b6" + integrity sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + +"@jest/test-result@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.4.6.tgz#b3df94c3d899c040f602cea296979844f61bdf69" + integrity sha512-fi9IGj3fkOrlMmhQqa/t9xum8jaJOOAi/lZlm6JXSc55rJMXKHxNDN1oCP39B0/DhNOa2OMupF9BcKZnNtXMOQ== + dependencies: + "@jest/console" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.4.6.tgz#447339b8a3d7b5436f50934df30854e442a9d904" + integrity sha512-3GL+nsf6E1PsyNsJuvPyIz+DwFuCtBdtvPpm/LMXVkBJbdFvQYCDpccYT56qq5BGniXWlE81n2qk1sdXfZebnw== + dependencies: + "@jest/test-result" "^27.4.6" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.6" + jest-runtime "^27.4.6" + +"@jest/transform@^27.4.6": + version "27.4.6" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.4.6.tgz#153621940b1ed500305eacdb31105d415dc30231" + integrity sha512-9MsufmJC8t5JTpWEQJ0OcOOAXaH5ioaIX6uHVBLBMoCZPfKKQF+EqP8kACAvCZ0Y1h2Zr3uOccg8re+Dr5jxyw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.4.2" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.6" + jest-regex-util "^27.4.0" + jest-util "^27.4.2" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" + integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + "@mapbox/node-pre-gyp@^1.0.0": version "1.0.8" resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz#32abc8a5c624bc4e46c43d84dfb8b26d33a96f58" @@ -96,11 +565,63 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@sqltools/formatter@^1.2.2": version "1.2.3" resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.1.18" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" + integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + "@types/bcrypt@^5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-5.0.0.tgz#a835afa2882d165aff5690893db314eaa98b9f20" @@ -147,6 +668,40 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^27.4.0": + version "27.4.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.0.tgz#037ab8b872067cae842a320841693080f9cb84ed" + integrity sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ== + dependencies: + jest-diff "^27.0.0" + pretty-format "^27.0.0" + "@types/joi@^17.2.3": version "17.2.3" resolved "https://registry.yarnpkg.com/@types/joi/-/joi-17.2.3.tgz#b7768ed9d84f1ebd393328b9f97c1cf3d2b94798" @@ -195,6 +750,11 @@ dependencies: "@types/node" "*" +"@types/prettier@^2.1.5": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.3.tgz#a3c65525b91fca7da00ab1a3ac2b5a2a4afbffbf" + integrity sha512-QzSuZMBuG5u8HqYz01qtMdg/Jfctlnvj1z/lYnIDXs/golxw0fxtRAHd9KrzjR7Yxz1qVeI00o0kiO3PmVdJ9w== + "@types/qs@*": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -213,6 +773,11 @@ "@types/mime" "^1" "@types/node" "*" +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + "@types/strip-bom@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" @@ -228,6 +793,18 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== +"@types/yargs-parser@*": + version "20.2.1" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== + +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + dependencies: + "@types/yargs-parser" "*" + "@types/zen-observable@0.8.3": version "0.8.3" resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" @@ -313,6 +890,11 @@ "@typescript-eslint/types" "5.10.0" eslint-visitor-keys "^3.0.0" +abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -326,12 +908,30 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.7.0: +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4, acorn@^8.7.0: version "8.7.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== @@ -353,11 +953,25 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +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-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" @@ -365,12 +979,17 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: 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== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= -anymatch@~3.1.2: +anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== @@ -406,6 +1025,13 @@ arg@^4.1.0: 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" @@ -421,6 +1047,72 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +babel-jest@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.4.6.tgz#4d024e69e241cdf4f396e453a07100f44f7ce314" + integrity sha512-qZL0JT0HS1L+lOuH+xC2DVASR3nunZi/ozGhpgauJHgmI7f8rudxf6hUjEHympdQ/J64CdKmPkgfJ+A3U6QCrg== + dependencies: + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.4.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + 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@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz#d7831fc0f93573788d80dee7e682482da4c730d6" + integrity sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@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@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz#70d0e676a282ccb200fbabd7f415db5fdf393bca" + integrity sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg== + dependencies: + babel-plugin-jest-hoist "^27.4.0" + 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" @@ -475,6 +1167,36 @@ braces@^3.0.1, braces@~3.0.2: dependencies: fill-range "^7.0.1" +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserslist@^4.17.5: + version "4.19.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== + dependencies: + caniuse-lite "^1.0.30001286" + electron-to-chromium "^1.4.17" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + +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" @@ -516,6 +1238,21 @@ callsites@^3.0.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.30001286: + version "1.0.30001301" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz#ebc9086026534cab0dab99425d9c3b4425e5f450" + integrity sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA== + celebrate@^15.0.0: version "15.0.0" resolved "https://registry.yarnpkg.com/celebrate/-/celebrate-15.0.0.tgz#2651237146ea03600d0d1244478782c06270d243" @@ -525,6 +1262,15 @@ celebrate@^15.0.0: joi "17.x.x" lodash "4.17.x" +chalk@^2.0.0: + 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" + chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -533,6 +1279,11 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.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== + chokidar@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" @@ -553,6 +1304,16 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== +ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + class-transformer@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" @@ -579,6 +1340,23 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +color-convert@^1.9.0: + 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" @@ -586,6 +1364,11 @@ color-convert@^2.0.1: 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 sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" @@ -596,6 +1379,13 @@ color-support@^1.1.2: resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== +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" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -628,6 +1418,13 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -656,7 +1453,7 @@ create-require@^1.1.0: 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.2: +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== @@ -665,6 +1462,32 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + date-fns@^2.28.0: version "2.28.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" @@ -677,18 +1500,38 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== dependencies: ms "2.1.2" -deep-is@^0.1.3: +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + +deep-is@^0.1.3, 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.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -709,6 +1552,11 @@ detect-libc@^1.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +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== + dicer@0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" @@ -717,6 +1565,11 @@ dicer@0.2.5: readable-stream "1.1.x" streamsearch "0.1.2" +diff-sequences@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" + integrity sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -736,6 +1589,13 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + dotenv@^14.2.0: version "14.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.2.0.tgz#7e77fd5dd6cff5942c4496e1acf2d0f37a9e67aa" @@ -765,6 +1625,16 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= +electron-to-chromium@^1.4.17: + version "1.4.49" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.49.tgz#5b6a3dc032590beef4be485a4b0b3fe7d0e3dfd7" + integrity sha512-k/0t1TRfonHIp8TJKfjBu2cKj8MqYTiEpOhci+q7CVEE5xnCQnx1pTa+V8b/sdhe4S3PR4p4iceEQWhGrKQORQ== + +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -785,11 +1655,33 @@ escape-html@1.0.3, escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= +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 sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +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== +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-config-prettier@6.15.0: version "6.15.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" @@ -892,6 +1784,11 @@ espree@^9.2.0, espree@^9.3.0: acorn-jsx "^5.3.1" eslint-visitor-keys "^3.1.0" +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.0: version "1.4.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" @@ -926,6 +1823,36 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +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" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expect@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.4.6.tgz#f335e128b0335b6ceb4fcab67ece7cbd14c942e6" + integrity sha512-1M/0kAALIaj5LaG66sFJTbRsWTADnylly82cu4bspI0nl+pgP4E6Bh/aqdHlTUjul06K7xQnnrAoqfxVU0+/ag== + dependencies: + "@jest/types" "^27.4.2" + jest-get-type "^27.4.0" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + express-async-errors@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/express-async-errors/-/express-async-errors-3.1.1.tgz#6053236d61d21ddef4892d6bd1d736889fc9da41" @@ -988,12 +1915,12 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.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: +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -1005,6 +1932,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + 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" @@ -1032,6 +1966,14 @@ finalhandler@~1.1.2: statuses "~1.5.0" 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" + flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -1045,6 +1987,15 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -1067,7 +2018,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -1097,16 +2048,31 @@ gauge@^3.0.0: strip-ansi "^6.0.1" wide-align "^1.1.2" +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-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-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== +get-stream@^6.0.0: + 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" @@ -1121,7 +2087,7 @@ glob-parent@^6.0.1: dependencies: is-glob "^4.0.3" -glob@^7.1.3, glob@^7.1.6: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -1133,6 +2099,11 @@ glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +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.6.0, globals@^13.9.0: version "13.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" @@ -1152,6 +2123,11 @@ globby@^11.0.4: merge2 "^1.4.1" slash "^3.0.0" +graceful-fs@^4.2.4: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + handlebars@^4.7.7: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" @@ -1164,6 +2140,11 @@ handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -1186,6 +2167,18 @@ highlight.js@^10.7.1: resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +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@1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" @@ -1197,6 +2190,15 @@ http-errors@1.8.1: statuses ">= 1.5.0 < 2" toidentifier "1.0.1" +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + https-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" @@ -1205,6 +2207,11 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +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== + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1235,6 +2242,14 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: 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" @@ -1282,6 +2297,11 @@ is-fullwidth-code-point@^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" @@ -1294,6 +2314,21 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +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-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -1309,24 +2344,521 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -joi@*, joi@17.x.x: - version "17.5.0" - resolved "https://registry.yarnpkg.com/joi/-/joi-17.5.0.tgz#7e66d0004b5045d971cf416a55fb61d33ac6e011" - integrity sha512-R7hR50COp7StzLnDi4ywOXHrBrgNXuUUfJWIR5lPY5Bm/pOD3jZaTwpluUXVLRWcoWZxkrHBBJ5hLxgnlehbdw== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== dependencies: - "@hapi/hoek" "^9.0.0" - "@hapi/topo" "^5.0.0" - "@sideway/address" "^4.1.3" - "@sideway/formula" "^3.0.0" - "@sideway/pinpoint" "^2.0.0" + "@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" -js-yaml@^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" +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.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.3" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.3.tgz#4bcae3103b94518117930d51283690960b50d3c2" + integrity sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.4.2.tgz#da2547ea47c6e6a5f6ed336151bd2075736eb4a5" + integrity sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A== + dependencies: + "@jest/types" "^27.4.2" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.4.6.tgz#d3af34c0eb742a967b1919fbb351430727bcea6c" + integrity sha512-UA7AI5HZrW4wRM72Ro80uRR2Fg+7nR0GESbSI/2M+ambbzVuA63mn5T1p3Z/wlhntzGpIG1xx78GP2YIkf6PhQ== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.4.6" + is-generator-fn "^2.0.0" + jest-each "^27.4.6" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + jest-runtime "^27.4.6" + jest-snapshot "^27.4.6" + jest-util "^27.4.2" + pretty-format "^27.4.6" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.4.7: + version "27.4.7" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.4.7.tgz#d00e759e55d77b3bcfea0715f527c394ca314e5a" + integrity sha512-zREYhvjjqe1KsGV15mdnxjThKNDgza1fhDT+iUsXWLCq3sxe9w5xnvyctcYVT5PcdLSjv7Y5dCwTS3FCF1tiuw== + dependencies: + "@jest/core" "^27.4.7" + "@jest/test-result" "^27.4.6" + "@jest/types" "^27.4.2" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + jest-config "^27.4.7" + jest-util "^27.4.2" + jest-validate "^27.4.6" + prompts "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.4.7: + version "27.4.7" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.4.7.tgz#4f084b2acbd172c8b43aa4cdffe75d89378d3972" + integrity sha512-xz/o/KJJEedHMrIY9v2ParIoYSrSVY6IVeE4z5Z3i101GoA5XgfbJz+1C8EYPsv7u7f39dS8F9v46BHDhn0vlw== + dependencies: + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.4.6" + "@jest/types" "^27.4.2" + babel-jest "^27.4.6" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + jest-circus "^27.4.6" + jest-environment-jsdom "^27.4.6" + jest-environment-node "^27.4.6" + jest-get-type "^27.4.0" + jest-jasmine2 "^27.4.6" + jest-regex-util "^27.4.0" + jest-resolve "^27.4.6" + jest-runner "^27.4.6" + jest-util "^27.4.2" + jest-validate "^27.4.6" + micromatch "^4.0.4" + pretty-format "^27.4.6" + slash "^3.0.0" + +jest-diff@^27.0.0, jest-diff@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.6.tgz#93815774d2012a2cbb6cf23f84d48c7a2618f98d" + integrity sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.4.0" + jest-get-type "^27.4.0" + pretty-format "^27.4.6" + +jest-docblock@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.4.0.tgz#06c78035ca93cbbb84faf8fce64deae79a59f69f" + integrity sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg== + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.4.6.tgz#e7e8561be61d8cc6dbf04296688747ab186c40ff" + integrity sha512-n6QDq8y2Hsmn22tRkgAk+z6MCX7MeVlAzxmZDshfS2jLcaBlyhpF3tZSJLR+kXmh23GEvS0ojMR8i6ZeRvpQcA== + dependencies: + "@jest/types" "^27.4.2" + chalk "^4.0.0" + jest-get-type "^27.4.0" + jest-util "^27.4.2" + pretty-format "^27.4.6" + +jest-environment-jsdom@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.4.6.tgz#c23a394eb445b33621dfae9c09e4c8021dea7b36" + integrity sha512-o3dx5p/kHPbUlRvSNjypEcEtgs6LmvESMzgRFQE6c+Prwl2JLA4RZ7qAnxc5VM8kutsGRTB15jXeeSbJsKN9iA== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/fake-timers" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-mock "^27.4.6" + jest-util "^27.4.2" + jsdom "^16.6.0" + +jest-environment-node@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.4.6.tgz#ee8cd4ef458a0ef09d087c8cd52ca5856df90242" + integrity sha512-yfHlZ9m+kzTKZV0hVfhVu6GuDxKAYeFHrfulmy7Jxwsq4V7+ZK7f+c0XP/tbVDMQW7E4neG2u147hFkuVz0MlQ== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/fake-timers" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + jest-mock "^27.4.6" + jest-util "^27.4.2" + +jest-get-type@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" + integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== + +jest-haste-map@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.4.6.tgz#c60b5233a34ca0520f325b7e2cc0a0140ad0862a" + integrity sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ== + dependencies: + "@jest/types" "^27.4.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^27.4.0" + jest-serializer "^27.4.0" + jest-util "^27.4.2" + jest-worker "^27.4.6" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.4.6.tgz#109e8bc036cb455950ae28a018f983f2abe50127" + integrity sha512-uAGNXF644I/whzhsf7/qf74gqy9OuhvJ0XYp8SDecX2ooGeaPnmJMjXjKt0mqh1Rl5dtRGxJgNrHlBQIBfS5Nw== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/source-map" "^27.4.0" + "@jest/test-result" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.4.6" + is-generator-fn "^2.0.0" + jest-each "^27.4.6" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + jest-runtime "^27.4.6" + jest-snapshot "^27.4.6" + jest-util "^27.4.2" + pretty-format "^27.4.6" + throat "^6.0.1" + +jest-leak-detector@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.4.6.tgz#ed9bc3ce514b4c582637088d9faf58a33bd59bf4" + integrity sha512-kkaGixDf9R7CjHm2pOzfTxZTQQQ2gHTIWKY/JZSiYTc90bZp8kSZnUMS3uLAfwTZwc0tcMRoEX74e14LG1WapA== + dependencies: + jest-get-type "^27.4.0" + pretty-format "^27.4.6" + +jest-matcher-utils@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.4.6.tgz#53ca7f7b58170638590e946f5363b988775509b8" + integrity sha512-XD4PKT3Wn1LQnRAq7ZsTI0VRuEc9OrCPFiO1XL7bftTGmfNF0DcEwMHRgqiu7NGf8ZoZDREpGrCniDkjt79WbA== + dependencies: + chalk "^4.0.0" + jest-diff "^27.4.6" + jest-get-type "^27.4.0" + pretty-format "^27.4.6" + +jest-message-util@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.4.6.tgz#9fdde41a33820ded3127465e1a5896061524da31" + integrity sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.4.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.4" + pretty-format "^27.4.6" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.4.6.tgz#77d1ba87fbd33ccb8ef1f061697e7341b7635195" + integrity sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.4.0.tgz#e4c45b52653128843d07ad94aec34393ea14fbca" + integrity sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg== + +jest-resolve-dependencies@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.6.tgz#fc50ee56a67d2c2183063f6a500cc4042b5e2327" + integrity sha512-W85uJZcFXEVZ7+MZqIPCscdjuctruNGXUZ3OHSXOfXR9ITgbUKeHj+uGcies+0SsvI5GtUfTw4dY7u9qjTvQOw== + dependencies: + "@jest/types" "^27.4.2" + jest-regex-util "^27.4.0" + jest-snapshot "^27.4.6" + +jest-resolve@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.4.6.tgz#2ec3110655e86d5bfcfa992e404e22f96b0b5977" + integrity sha512-SFfITVApqtirbITKFAO7jOVN45UgFzcRdQanOFzjnbd+CACDoyeX7206JyU92l4cRr73+Qy/TlW51+4vHGt+zw== + dependencies: + "@jest/types" "^27.4.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.6" + jest-pnp-resolver "^1.2.2" + jest-util "^27.4.2" + jest-validate "^27.4.6" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.4.6.tgz#1d390d276ec417e9b4d0d081783584cbc3e24773" + integrity sha512-IDeFt2SG4DzqalYBZRgbbPmpwV3X0DcntjezPBERvnhwKGWTW7C5pbbA5lVkmvgteeNfdd/23gwqv3aiilpYPg== + dependencies: + "@jest/console" "^27.4.6" + "@jest/environment" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-docblock "^27.4.0" + jest-environment-jsdom "^27.4.6" + jest-environment-node "^27.4.6" + jest-haste-map "^27.4.6" + jest-leak-detector "^27.4.6" + jest-message-util "^27.4.6" + jest-resolve "^27.4.6" + jest-runtime "^27.4.6" + jest-util "^27.4.2" + jest-worker "^27.4.6" + source-map-support "^0.5.6" + throat "^6.0.1" + +jest-runtime@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.4.6.tgz#83ae923818e3ea04463b22f3597f017bb5a1cffa" + integrity sha512-eXYeoR/MbIpVDrjqy5d6cGCFOYBFFDeKaNWqTp0h6E74dK0zLHzASQXJpl5a2/40euBmKnprNLJ0Kh0LCndnWQ== + dependencies: + "@jest/environment" "^27.4.6" + "@jest/fake-timers" "^27.4.6" + "@jest/globals" "^27.4.6" + "@jest/source-map" "^27.4.0" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.6" + jest-message-util "^27.4.6" + jest-mock "^27.4.6" + jest-regex-util "^27.4.0" + jest-resolve "^27.4.6" + jest-snapshot "^27.4.6" + jest-util "^27.4.2" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-serializer@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.4.0.tgz#34866586e1cae2388b7d12ffa2c7819edef5958a" + integrity sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.4.6.tgz#e2a3b4fff8bdce3033f2373b2e525d8b6871f616" + integrity sha512-fafUCDLQfzuNP9IRcEqaFAMzEe7u5BF7mude51wyWv7VRex60WznZIC7DfKTgSIlJa8aFzYmXclmN328aqSDmQ== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.4.6" + graceful-fs "^4.2.4" + jest-diff "^27.4.6" + jest-get-type "^27.4.0" + jest-haste-map "^27.4.6" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + jest-util "^27.4.2" + natural-compare "^1.4.0" + pretty-format "^27.4.6" + semver "^7.3.2" + +jest-util@^27.0.0, jest-util@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.4.2.tgz#ed95b05b1adfd761e2cda47e0144c6a58e05a621" + integrity sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.4" + picomatch "^2.2.3" + +jest-validate@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.4.6.tgz#efc000acc4697b6cf4fa68c7f3f324c92d0c4f1f" + integrity sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ== + dependencies: + "@jest/types" "^27.4.2" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.4.0" + leven "^3.1.0" + pretty-format "^27.4.6" + +jest-watcher@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.4.6.tgz#673679ebeffdd3f94338c24f399b85efc932272d" + integrity sha512-yKQ20OMBiCDigbD0quhQKLkBO+ObGN79MO4nT7YaCuQ5SM+dkBNWE8cZX0FjU6czwMvWw6StWbe+Wv4jJPJ+fw== + dependencies: + "@jest/test-result" "^27.4.6" + "@jest/types" "^27.4.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.4.2" + string-length "^4.0.1" + +jest-worker@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.6.tgz#5d2d93db419566cb680752ca0792780e71b3273e" + integrity sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^27.4.7: + version "27.4.7" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.4.7.tgz#87f74b9026a1592f2da05b4d258e57505f28eca4" + integrity sha512-8heYvsx7nV/m8m24Vk26Y87g73Ba6ueUd0MWed/NXMhSZIm62U/llVbS0PJe1SHunbyXjJ/BqG1z9bFjGUIvTg== + dependencies: + "@jest/core" "^27.4.7" + import-local "^3.0.2" + jest-cli "^27.4.7" + +joi@*, joi@17.x.x: + version "17.5.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.5.0.tgz#7e66d0004b5045d971cf416a55fb61d33ac6e011" + integrity sha512-R7hR50COp7StzLnDi4ywOXHrBrgNXuUUfJWIR5lPY5Bm/pOD3jZaTwpluUXVLRWcoWZxkrHBBJ5hLxgnlehbdw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.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.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" +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +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-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" @@ -1337,6 +2869,13 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json5@2.x, json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -1377,6 +2916,16 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.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== + +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" @@ -1385,6 +2934,21 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +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" + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -1415,6 +2979,11 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= +lodash.memoize@4.x: + version "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" @@ -1425,7 +2994,7 @@ lodash.once@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= -lodash@4.17.x: +lodash@4.17.x, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -1437,18 +3006,25 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -make-dir@^3.1.0: +make-dir@^3.0.0, make-dir@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== dependencies: semver "^6.0.0" -make-error@^1.1.1: +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" @@ -1459,6 +3035,11 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= +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" @@ -1482,7 +3063,7 @@ mime-db@1.51.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== -mime-types@~2.1.24: +mime-types@^2.1.12, mime-types@~2.1.24: version "2.1.34" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== @@ -1494,6 +3075,11 @@ mime@1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +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== + minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -1598,6 +3184,16 @@ node-fetch@^2.6.5: 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 sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + nodemailer@^6.7.2: version "6.7.2" resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0" @@ -1615,6 +3211,13 @@ normalize-path@^3.0.0, normalize-path@~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.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" + npmlog@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" @@ -1625,6 +3228,11 @@ npmlog@^5.0.1: gauge "^3.0.0" set-blocking "^2.0.0" +nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + 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" @@ -1644,6 +3252,25 @@ once@^1.3.0: dependencies: wrappy "1" +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" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + optionator@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" @@ -1656,6 +3283,25 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +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-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-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" @@ -1675,27 +3321,32 @@ parse5-htmlparser2-tree-adapter@^6.0.0: dependencies: parse5 "^6.0.1" +parse5@6.0.1, parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + 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 sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^3.1.0: +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== @@ -1766,11 +3417,28 @@ pgpass@1.x: 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.0.4, picomatch@^2.2.1, picomatch@^2.2.3: 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.4" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" + integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== + +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" + postgres-array@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" @@ -1798,6 +3466,11 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + 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" @@ -1810,11 +3483,28 @@ prettier@^2.5.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== +pretty-format@^27.0.0, pretty-format@^27.4.6: + version "27.4.6" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.6.tgz#1b784d2f53c68db31797b2348fa39b49e31846b7" + integrity sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + 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" @@ -1823,7 +3513,12 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" -punycode@^2.1.0: +psl@^1.1.33: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -1853,6 +3548,11 @@ raw-body@2.4.2: iconv-lite "0.4.24" unpipe "1.0.0" +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + readable-stream@1.1.x: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" @@ -1907,11 +3607,28 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +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@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + resolve@^1.0.0: version "1.21.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" @@ -1921,6 +3638,15 @@ resolve@^1.0.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.20.0: + version "1.21.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.1.tgz#1a88c73f5ca8ab0aabc8b888c4170de26c92c4cc" + integrity sha512-lfEImVbnolPuaSZuLQ52cAxPBHeI77sPwCOWRdy12UG/CNa8an7oBHH1R+Fp1/mUqSJi4c8TIP6FOIPSZAUrEQ== + dependencies: + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -1933,7 +3659,7 @@ rimraf@^2.6.1: dependencies: glob "^7.1.3" -rimraf@^3.0.2: +rimraf@^3.0.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== @@ -1967,23 +3693,30 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +semver@7.x, semver@^7.3.2, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0: +semver@^6.0.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - send@0.17.2: version "0.17.2" resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" @@ -2043,17 +3776,22 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -signal-exit@^3.0.0: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.6" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== +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.12, source-map-support@^0.5.17: +source-map-support@^0.5.12, source-map-support@^0.5.17, source-map-support@^0.5.6: 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== @@ -2061,16 +3799,38 @@ source-map-support@^0.5.12, source-map-support@^0.5.17: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.6.0, source-map@^0.6.1: +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, 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== +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + split2@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -2081,6 +3841,14 @@ streamsearch@0.1.2: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= +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@^1.0.2 || 2 || 3 || 4", 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" @@ -2121,6 +3889,16 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= +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-json-comments@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -2131,18 +3909,45 @@ strip-json-comments@^3.1.0, strip-json-comments@^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== -supports-color@^7.1.0: +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.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-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.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-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + tar@^6.1.11: version "6.1.11" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" @@ -2155,6 +3960,23 @@ tar@^6.1.11: mkdirp "^1.0.3" yallist "^4.0.0" +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +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-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -2174,6 +3996,21 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" +throat@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== + +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 sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + 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" @@ -2186,6 +4023,22 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -2196,6 +4049,20 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== +ts-jest@^27.1.3: + version "27.1.3" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.3.tgz#1f723e7e74027c4da92c0ffbd73287e8af2b2957" + integrity sha512-6Nlura7s6uM9BVUAoqLH7JHyMXjz8gluryjpPXxr3IxZdAXnU6FhjvVLHFtfd1vsE1p8zD1OJfskkc0jhTSnkA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^27.0.0" + json5 "2.x" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "20.x" + ts-node-dev@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-1.1.8.tgz#95520d8ab9d45fffa854d6668e2f8f9286241066" @@ -2275,11 +4142,28 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +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" @@ -2288,6 +4172,13 @@ type-is@^1.6.4, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + 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" @@ -2325,6 +4216,11 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.5.tgz#cdabb7d4954231d80cb4a927654c4655e51f4859" integrity sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ== +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -2357,16 +4253,68 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +v8-to-istanbul@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" + integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7: + 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" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -2375,6 +4323,15 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -2389,7 +4346,7 @@ wide-align@^1.1.2: dependencies: string-width "^1.0.2 || 2 || 3 || 4" -word-wrap@^1.2.3: +word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== @@ -2413,6 +4370,26 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^7.4.6: + version "7.5.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + xml2js@^0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" @@ -2426,6 +4403,11 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + xtend@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -2441,7 +4423,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@^20.2.2: +yargs-parser@20.x, 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== @@ -2451,7 +4433,7 @@ yargs-parser@^21.0.0: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== -yargs@^16.0.0: +yargs@^16.0.0, yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== From 333b57f3413e61e68e96fdd5f3894b9132695dbf Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 17:34:57 -0300 Subject: [PATCH 60/92] test: ensure the creation category returns 201 --- .../repositories/ICategoriesRepository.ts | 4 +- .../fakes/CategoriesFakeRepository.ts | 55 +++++++++++++++++++ .../controllers/CreateCategoryController.ts | 4 +- .../repositories/CategoriesRepository.ts | 10 +++- .../services/CreateCategoryService.ts | 9 ++- .../tests/CreateCategoryService.spec.ts | 21 +++++++ 6 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 src/modules/categories/domain/repositories/fakes/CategoriesFakeRepository.ts create mode 100644 src/modules/categories/services/tests/CreateCategoryService.spec.ts diff --git a/src/modules/categories/domain/repositories/ICategoriesRepository.ts b/src/modules/categories/domain/repositories/ICategoriesRepository.ts index 5b0bfef..98967fe 100644 --- a/src/modules/categories/domain/repositories/ICategoriesRepository.ts +++ b/src/modules/categories/domain/repositories/ICategoriesRepository.ts @@ -2,12 +2,12 @@ import { ICreateCategoryDTO } from '../dtos/ICreateCategoryDTO'; import { ICategory } from '../models/ICategory'; interface ICategoriesRepository { - create(data: ICreateCategoryDTO): Promise; + create(data: ICreateCategoryDTO): Promise; findByName(name: string): Promise; list(): Promise; findById(id: string): Promise; findByDelete(id: string): Promise; - save(category: ICategory): Promise; + save(category: ICategory): Promise; } export { ICategoriesRepository }; diff --git a/src/modules/categories/domain/repositories/fakes/CategoriesFakeRepository.ts b/src/modules/categories/domain/repositories/fakes/CategoriesFakeRepository.ts new file mode 100644 index 0000000..a0cc462 --- /dev/null +++ b/src/modules/categories/domain/repositories/fakes/CategoriesFakeRepository.ts @@ -0,0 +1,55 @@ +import { Category } from '../../../infra/typeorm/entities/Category'; +import { ICreateCategoryDTO } from '../../dtos/ICreateCategoryDTO'; +import { ICategory } from '../../models/ICategory'; +import { ICategoriesRepository } from '../ICategoriesRepository'; + +class CategoriesFakeRepository implements ICategoriesRepository { + categories: Category[] = []; + + async create({ name, description }: ICreateCategoryDTO): Promise { + const create = new Category(); + + Object.assign(create, { + name, + description, + }); + + this.categories.push(create); + + return create; + } + + async findByName(name: string): Promise { + const category = this.categories.find(category => category.name === name); + + return category; + } + + async list(): Promise { + const categories = this.categories; + + return categories; + } + + async findById(id: string): Promise { + const category = this.categories.find(category => category.id === id); + + return category; + } + + async findByDelete(id: string): Promise { + this.categories.find(category => category.id === id); + } + + async save(category: ICategory): Promise { + const findIndex = this.categories.findIndex( + findIndex => findIndex.id === category.id, + ); + + this.categories[findIndex] = category; + + return category; + } +} + +export { CategoriesFakeRepository }; diff --git a/src/modules/categories/infra/http/controllers/CreateCategoryController.ts b/src/modules/categories/infra/http/controllers/CreateCategoryController.ts index 8e84947..2543c99 100644 --- a/src/modules/categories/infra/http/controllers/CreateCategoryController.ts +++ b/src/modules/categories/infra/http/controllers/CreateCategoryController.ts @@ -8,12 +8,12 @@ class CreateCategoryController { const createCategoryService = container.resolve(CreateCategoryService); - await createCategoryService.execute({ + const category = await createCategoryService.execute({ name, description, }); - return response.status(201).send(); + return response.status(201).json(category); } } diff --git a/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts b/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts index 4203bd0..78c92c6 100644 --- a/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts +++ b/src/modules/categories/infra/typeorm/repositories/CategoriesRepository.ts @@ -21,8 +21,10 @@ class CategoriesRepository implements ICategoriesRepository { await this.repository.delete(id); } - async save(category: ICategory): Promise { + async save(category: ICategory): Promise { await this.repository.save(category); + + return category; } async list(): Promise { @@ -36,13 +38,15 @@ class CategoriesRepository implements ICategoriesRepository { return category; } - async create({ name, description }: ICreateCategoryDTO): Promise { + async create({ name, description }: ICreateCategoryDTO): Promise { const createCategory = this.repository.create({ name, description, }); - await this.repository.save(createCategory); + const category = await this.repository.save(createCategory); + + return category; } } diff --git a/src/modules/categories/services/CreateCategoryService.ts b/src/modules/categories/services/CreateCategoryService.ts index ced3686..71c3d82 100644 --- a/src/modules/categories/services/CreateCategoryService.ts +++ b/src/modules/categories/services/CreateCategoryService.ts @@ -1,7 +1,8 @@ -import { AppError } from '@shared/errors/AppError'; +import { AppError } from '../../../shared/errors/AppError'; import { inject, injectable } from 'tsyringe'; import { ICreateCategoryDTO } from '../domain/dtos/ICreateCategoryDTO'; import { ICategoriesRepository } from '../domain/repositories/ICategoriesRepository'; +import { ICategory } from '../domain/models/ICategory'; @injectable() class CreateCategoryService { @@ -10,17 +11,19 @@ class CreateCategoryService { private categoriesRepository: ICategoriesRepository, ) {} - async execute({ name, description }: ICreateCategoryDTO): Promise { + async execute({ name, description }: ICreateCategoryDTO): Promise { const categoryExists = await this.categoriesRepository.findByName(name); if (categoryExists) { throw new AppError('This category already exists.'); } - this.categoriesRepository.create({ + const category = this.categoriesRepository.create({ name, description, }); + + return category; } } diff --git a/src/modules/categories/services/tests/CreateCategoryService.spec.ts b/src/modules/categories/services/tests/CreateCategoryService.spec.ts new file mode 100644 index 0000000..50b6d0f --- /dev/null +++ b/src/modules/categories/services/tests/CreateCategoryService.spec.ts @@ -0,0 +1,21 @@ +import { CategoriesFakeRepository } from '../../domain/repositories/fakes/CategoriesFakeRepository'; +import { CreateCategoryService } from '../CreateCategoryService'; + +let createCategoryService: CreateCategoryService; +let categoriesFakeRepository: CategoriesFakeRepository; + +describe('Create Category', () => { + beforeEach(() => { + categoriesFakeRepository = new CategoriesFakeRepository(); + createCategoryService = new CreateCategoryService(categoriesFakeRepository); + }); + + it('should be able to create a category', async () => { + const category = await createCategoryService.execute({ + name: 'Category', + description: 'Category Description', + }); + + expect(category).toHaveProperty('id'); + }); +}); From 8671b94c3c7c7b5285e5c65f67c8c9f9d37ef37b Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 18:10:10 -0300 Subject: [PATCH 61/92] test: ensure the category returns 400 if created with the same name --- .../tests/CreateCategoryService.spec.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/modules/categories/services/tests/CreateCategoryService.spec.ts b/src/modules/categories/services/tests/CreateCategoryService.spec.ts index 50b6d0f..c3fc9e0 100644 --- a/src/modules/categories/services/tests/CreateCategoryService.spec.ts +++ b/src/modules/categories/services/tests/CreateCategoryService.spec.ts @@ -1,3 +1,4 @@ +import { AppError } from '../../../../shared/errors/AppError'; import { CategoriesFakeRepository } from '../../domain/repositories/fakes/CategoriesFakeRepository'; import { CreateCategoryService } from '../CreateCategoryService'; @@ -18,4 +19,23 @@ describe('Create Category', () => { expect(category).toHaveProperty('id'); }); + + it('should not be able to create a new category with name exists', async () => { + const category = { + name: 'Category', + description: 'Category Description', + }; + + await createCategoryService.execute({ + name: category.name, + description: category.description, + }); + + await expect( + createCategoryService.execute({ + name: category.name, + description: category.description, + }), + ).rejects.toEqual(new AppError('This category already exists.')); + }); }); From 4690ca74143d6ddd50376449df64c693c6dbb83e Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Fri, 21 Jan 2022 18:46:56 -0300 Subject: [PATCH 62/92] test: ensure that listing all categories returns 200 --- .../tests/ListCategoriesService.spec.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/modules/categories/services/tests/ListCategoriesService.spec.ts diff --git a/src/modules/categories/services/tests/ListCategoriesService.spec.ts b/src/modules/categories/services/tests/ListCategoriesService.spec.ts new file mode 100644 index 0000000..c3da467 --- /dev/null +++ b/src/modules/categories/services/tests/ListCategoriesService.spec.ts @@ -0,0 +1,23 @@ +import { CategoriesFakeRepository } from '../../domain/repositories/fakes/CategoriesFakeRepository'; +import { ListCategoriesService } from '../ListCategoriesService'; + +let listCategoriesService: ListCategoriesService; +let categoriesFakeRepository: CategoriesFakeRepository; + +describe('List Categories', () => { + beforeEach(() => { + categoriesFakeRepository = new CategoriesFakeRepository(); + listCategoriesService = new ListCategoriesService(categoriesFakeRepository); + }); + + it('should be able to list all categories', async () => { + const category = await categoriesFakeRepository.create({ + name: 'Category', + description: 'Category Description', + }); + + const categories = await listCategoriesService.execute(); + + expect(categories).toEqual([category]); + }); +}); From c070815f679e5930c9b157929758188c2439746c Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 01:45:08 -0300 Subject: [PATCH 63/92] test: ensure user creation returns 201 --- .../domain/repositories/IUsersRepository.ts | 2 +- .../repositories/fakes/UsersFakeRepository.ts | 56 +++++++++++++++++++ .../typeorm/repositories/UsersRepository.ts | 4 +- .../fakes/HashProviderFakeRepository.ts | 13 +++++ .../users/services/CreateUserService.ts | 2 +- .../services/tests/CreateUserService.spec.ts | 31 ++++++++++ 6 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 src/modules/users/domain/repositories/fakes/UsersFakeRepository.ts create mode 100644 src/modules/users/providers/fakes/HashProviderFakeRepository.ts create mode 100644 src/modules/users/services/tests/CreateUserService.spec.ts diff --git a/src/modules/users/domain/repositories/IUsersRepository.ts b/src/modules/users/domain/repositories/IUsersRepository.ts index 0bb589d..68976ca 100644 --- a/src/modules/users/domain/repositories/IUsersRepository.ts +++ b/src/modules/users/domain/repositories/IUsersRepository.ts @@ -3,7 +3,7 @@ import { IUser } from '../models/IUser'; interface IUsersRepository { findByDelete(id: string): Promise; - save(user: IUser): Promise; + save(user: IUser): Promise; findAll(): Promise; create(data: ICreateUserDTO): Promise; findByEmail(email: string): Promise; diff --git a/src/modules/users/domain/repositories/fakes/UsersFakeRepository.ts b/src/modules/users/domain/repositories/fakes/UsersFakeRepository.ts new file mode 100644 index 0000000..bb2e98d --- /dev/null +++ b/src/modules/users/domain/repositories/fakes/UsersFakeRepository.ts @@ -0,0 +1,56 @@ +import { User } from '../../../infra/typeorm/entities/User'; +import { ICreateUserDTO } from '../../dtos/ICreateUserDTO'; +import { IUser } from '../../models/IUser'; +import { IUsersRepository } from '../IUsersRepository'; + +class UsersFakeRepository implements IUsersRepository { + users: User[] = []; + + async findByDelete(id: string): Promise { + this.users.find(user => user.id === id); + } + + async save(user: IUser): Promise { + const findIndex = this.users.findIndex( + findIndex => findIndex.id === user.id, + ); + + this.users[findIndex] = user; + + return user; + } + + async findAll(): Promise { + const users = this.users; + + return users; + } + + async create({ name, email, password }: ICreateUserDTO): Promise { + const create = new User(); + + Object.assign(create, { + name, + email, + password, + }); + + this.users.push(create); + + return create; + } + + async findByEmail(email: string): Promise { + const user = this.users.find(user => user.email === email); + + return user; + } + + async findById(id: string): Promise { + const user = this.users.find(user => user.id === id); + + return user; + } +} + +export { UsersFakeRepository }; diff --git a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts index 99d2934..fd5d09c 100644 --- a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts +++ b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts @@ -15,8 +15,10 @@ class UsersRepository implements IUsersRepository { await this.repository.delete(id); } - async save(user: IUser): Promise { + async save(user: IUser): Promise { await this.repository.save(user); + + return user; } findAll(): Promise { diff --git a/src/modules/users/providers/fakes/HashProviderFakeRepository.ts b/src/modules/users/providers/fakes/HashProviderFakeRepository.ts new file mode 100644 index 0000000..5749b0d --- /dev/null +++ b/src/modules/users/providers/fakes/HashProviderFakeRepository.ts @@ -0,0 +1,13 @@ +import { IHashProvider } from '../models/IHashProvider'; + +class HashProviderFakeRepository implements IHashProvider { + async generateHash(payload: string): Promise { + return payload; + } + + async compareHash(payload: string, hashed: string): Promise { + return payload === hashed; + } +} + +export { HashProviderFakeRepository }; diff --git a/src/modules/users/services/CreateUserService.ts b/src/modules/users/services/CreateUserService.ts index 3e1335b..42ee45e 100644 --- a/src/modules/users/services/CreateUserService.ts +++ b/src/modules/users/services/CreateUserService.ts @@ -1,4 +1,4 @@ -import { AppError } from '@shared/errors/AppError'; +import { AppError } from '../../../shared/errors/AppError'; import { inject, injectable } from 'tsyringe'; import { ICreateUserDTO } from '../domain/dtos/ICreateUserDTO'; import { IUser } from '../domain/models/IUser'; diff --git a/src/modules/users/services/tests/CreateUserService.spec.ts b/src/modules/users/services/tests/CreateUserService.spec.ts new file mode 100644 index 0000000..73e18c0 --- /dev/null +++ b/src/modules/users/services/tests/CreateUserService.spec.ts @@ -0,0 +1,31 @@ +//import { AppError } from '../../../../shared/errors/AppError'; +import { UsersFakeRepository } from '../../domain/repositories/fakes/UsersFakeRepository'; +import { CreateUserService } from '../CreateUserService'; +import { HashProviderFakeRepository } from '../../providers/fakes/HashProviderFakeRepository'; + +let createUserService: CreateUserService; +let usersFakeRepository: UsersFakeRepository; +let hashProviderFakeRepository: HashProviderFakeRepository; + +describe('Create User', () => { + beforeEach(() => { + usersFakeRepository = new UsersFakeRepository(); + hashProviderFakeRepository = new HashProviderFakeRepository(); + createUserService = new CreateUserService( + usersFakeRepository, + hashProviderFakeRepository, + ); + }); + + it('should be able to create a user', async () => { + const createUser = await createUserService.execute({ + name: 'Nome Test', + email: 'test@test.com', + password: '123456', + }); + + expect(createUser).toHaveProperty('id'); + }); + + //it('should not be able to create a new category with name exists', async () => {}); +}); From 30d1371fc1f7a7a5240d53040d34c99168290fcd Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 01:57:07 -0300 Subject: [PATCH 64/92] test: ensure the user returns 400 if created with the same email --- .../services/tests/CreateUserService.spec.ts | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/modules/users/services/tests/CreateUserService.spec.ts b/src/modules/users/services/tests/CreateUserService.spec.ts index 73e18c0..f0fc0c1 100644 --- a/src/modules/users/services/tests/CreateUserService.spec.ts +++ b/src/modules/users/services/tests/CreateUserService.spec.ts @@ -1,4 +1,4 @@ -//import { AppError } from '../../../../shared/errors/AppError'; +import { AppError } from '../../../../shared/errors/AppError'; import { UsersFakeRepository } from '../../domain/repositories/fakes/UsersFakeRepository'; import { CreateUserService } from '../CreateUserService'; import { HashProviderFakeRepository } from '../../providers/fakes/HashProviderFakeRepository'; @@ -27,5 +27,25 @@ describe('Create User', () => { expect(createUser).toHaveProperty('id'); }); - //it('should not be able to create a new category with name exists', async () => {}); + it('should not be able to create two users with the same email', async () => { + const user = { + name: 'Nome Test', + email: 'test@test.com', + password: '123456', + }; + + await createUserService.execute({ + name: user.name, + email: user.email, + password: user.password, + }); + + expect( + createUserService.execute({ + name: user.name, + email: user.email, + password: user.password, + }), + ).rejects.toBeInstanceOf(AppError); + }); }); From 99fecc522f72ccc2125c1eee13467ae3df922954 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 02:28:39 -0300 Subject: [PATCH 65/92] test: ensure login authentication --- .../users/services/CreateSessionService.ts | 4 +- .../tests/CreateSessionService.spec.ts | 42 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/modules/users/services/tests/CreateSessionService.spec.ts diff --git a/src/modules/users/services/CreateSessionService.ts b/src/modules/users/services/CreateSessionService.ts index 9803529..fd0fd30 100644 --- a/src/modules/users/services/CreateSessionService.ts +++ b/src/modules/users/services/CreateSessionService.ts @@ -1,5 +1,5 @@ -import authConfig from '@config/auth'; -import { AppError } from '@shared/errors/AppError'; +import authConfig from '../../../config/auth'; +import { AppError } from '../../../shared/errors/AppError'; import { sign } from 'jsonwebtoken'; import { inject, injectable } from 'tsyringe'; import { IUsersRepository } from '../domain/repositories/IUsersRepository'; diff --git a/src/modules/users/services/tests/CreateSessionService.spec.ts b/src/modules/users/services/tests/CreateSessionService.spec.ts new file mode 100644 index 0000000..01dc70b --- /dev/null +++ b/src/modules/users/services/tests/CreateSessionService.spec.ts @@ -0,0 +1,42 @@ +import { UsersFakeRepository } from '../../domain/repositories/fakes/UsersFakeRepository'; +import { HashProviderFakeRepository } from '../../providers/fakes/HashProviderFakeRepository'; +import { CreateSessionService } from '../CreateSessionService'; +import { CreateUserService } from '../CreateUserService'; + +let createSessionService: CreateSessionService; +let createUserService: CreateUserService; +let usersFakeRepository: UsersFakeRepository; +let hashProviderFakeRepository: HashProviderFakeRepository; + +describe('Create Session', () => { + beforeEach(() => { + usersFakeRepository = new UsersFakeRepository(); + hashProviderFakeRepository = new HashProviderFakeRepository(); + createSessionService = new CreateSessionService( + usersFakeRepository, + hashProviderFakeRepository, + ); + + createUserService = new CreateUserService( + usersFakeRepository, + hashProviderFakeRepository, + ); + }); + + it('should be able to authenticate', async () => { + const user = { + name: 'Nome Test', + email: 'test@test.com', + password: '123456', + }; + + await createUserService.execute(user); + + const result = await createSessionService.execute({ + email: user.email, + password: user.password, + }); + + expect(result).toHaveProperty('token'); + }); +}); From 1d5e444a0447155ea16bf66c68894a7e8555ddd9 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 02:30:56 -0300 Subject: [PATCH 66/92] ensure it returns 401 if it tries to authenticate with non-existent user --- .../users/services/tests/CreateSessionService.spec.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/modules/users/services/tests/CreateSessionService.spec.ts b/src/modules/users/services/tests/CreateSessionService.spec.ts index 01dc70b..67cf3f1 100644 --- a/src/modules/users/services/tests/CreateSessionService.spec.ts +++ b/src/modules/users/services/tests/CreateSessionService.spec.ts @@ -1,3 +1,4 @@ +import { AppError } from '../../../../shared/errors/AppError'; import { UsersFakeRepository } from '../../domain/repositories/fakes/UsersFakeRepository'; import { HashProviderFakeRepository } from '../../providers/fakes/HashProviderFakeRepository'; import { CreateSessionService } from '../CreateSessionService'; @@ -39,4 +40,13 @@ describe('Create Session', () => { expect(result).toHaveProperty('token'); }); + + it('should not be able to authenticate with non existent user', async () => { + expect( + createSessionService.execute({ + email: 'teste@teste.com', + password: '123456', + }), + ).rejects.toBeInstanceOf(AppError); + }); }); From 97c951287ba57355f7e29ab936fe990263f6a334 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 02:36:43 -0300 Subject: [PATCH 67/92] test: ensure it returns 401 if it tries to authenticate with wrong password --- .../services/tests/CreateSessionService.spec.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/modules/users/services/tests/CreateSessionService.spec.ts b/src/modules/users/services/tests/CreateSessionService.spec.ts index 67cf3f1..06e1f8b 100644 --- a/src/modules/users/services/tests/CreateSessionService.spec.ts +++ b/src/modules/users/services/tests/CreateSessionService.spec.ts @@ -49,4 +49,19 @@ describe('Create Session', () => { }), ).rejects.toBeInstanceOf(AppError); }); + + it('should not be able to authenticate with wrong password', async () => { + await usersFakeRepository.create({ + name: 'Nome Test', + email: 'test@test.com', + password: '123456', + }); + + expect( + createSessionService.execute({ + email: 'test@test.com', + password: '123321', + }), + ).rejects.toBeInstanceOf(AppError); + }); }); From e98bec0c7a5680e8e8469d8f7665e384ad05dc63 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 03:25:02 -0300 Subject: [PATCH 68/92] test: ensure category is excluded --- .../tests/DeleteCategoryService.spec.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/modules/categories/services/tests/DeleteCategoryService.spec.ts diff --git a/src/modules/categories/services/tests/DeleteCategoryService.spec.ts b/src/modules/categories/services/tests/DeleteCategoryService.spec.ts new file mode 100644 index 0000000..0a4db5d --- /dev/null +++ b/src/modules/categories/services/tests/DeleteCategoryService.spec.ts @@ -0,0 +1,27 @@ +import { CategoriesFakeRepository } from '../../domain/repositories/fakes/CategoriesFakeRepository'; +import { CreateCategoryService } from '../CreateCategoryService'; + +let createCategoryService: CreateCategoryService; +let categoriesFakeRepository: CategoriesFakeRepository; + +describe('Delete Category', () => { + beforeEach(() => { + categoriesFakeRepository = new CategoriesFakeRepository(); + createCategoryService = new CreateCategoryService(categoriesFakeRepository); + }); + + it('should be able to delete a category', async () => { + const category = await createCategoryService.execute({ + name: 'Category', + description: 'Category Description', + }); + + expect(category).toHaveProperty('id'); + + const deleteCategory = await categoriesFakeRepository.findByDelete( + category.id, + ); + + expect(deleteCategory).toBeUndefined(); + }); +}); From 4990b541f91b85e299bf2c2e69ebfa7d24fb9c48 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 16:32:52 -0300 Subject: [PATCH 69/92] test: ensure object creation returns 201 --- .../infra/typeorm/entities/ObjectLostFound.ts | 2 +- .../tests/CreateObjectService.spec.ts | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/modules/objects/services/tests/CreateObjectService.spec.ts diff --git a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts index 3d6d18d..941fb09 100644 --- a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts +++ b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts @@ -1,4 +1,4 @@ -import { Category } from '@modules/categories/infra/typeorm/entities/Category'; +import { Category } from '../../../../categories/infra/typeorm/entities/Category'; import { IObject } from '@modules/objects/domain/models/IObject'; import { diff --git a/src/modules/objects/services/tests/CreateObjectService.spec.ts b/src/modules/objects/services/tests/CreateObjectService.spec.ts new file mode 100644 index 0000000..4b7c008 --- /dev/null +++ b/src/modules/objects/services/tests/CreateObjectService.spec.ts @@ -0,0 +1,28 @@ +import { ObjectsFakeRepository } from '../../../objects/domain/repositories/fakes/ObjectsFakeRepository'; +import { CreateObjectService } from '../CreateObjectService'; + +let createObjectService: CreateObjectService; +let objectsFakeRepository: ObjectsFakeRepository; + +enum TypeEnum { + Found = 'Perdido', + Lost = 'Achado', +} + +describe('Create Object', () => { + beforeEach(() => { + objectsFakeRepository = new ObjectsFakeRepository(); + createObjectService = new CreateObjectService(objectsFakeRepository); + }); + + it('should be able to create a category', async () => { + const object = await createObjectService.execute({ + name: 'Object', + comments: 'Comments', + type: TypeEnum.Found, + category_id: 'Category', + }); + + expect(object).toHaveProperty('id'); + }); +}); From 92d91ccfe081f8b7100cd1eb7cd16370e937aa69 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 16:33:27 -0300 Subject: [PATCH 70/92] chore: adding relations --- src/modules/users/infra/typeorm/entities/UserToken.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/modules/users/infra/typeorm/entities/UserToken.ts b/src/modules/users/infra/typeorm/entities/UserToken.ts index 13bd04f..5db9797 100644 --- a/src/modules/users/infra/typeorm/entities/UserToken.ts +++ b/src/modules/users/infra/typeorm/entities/UserToken.ts @@ -4,11 +4,14 @@ import { CreateDateColumn, Entity, Generated, + JoinColumn, + ManyToOne, PrimaryColumn, UpdateDateColumn, } from 'typeorm'; import { v4 as uuidV4 } from 'uuid'; +import { User } from './User'; @Entity('user_tokens') class UserToken implements IUserToken { @@ -22,6 +25,10 @@ class UserToken implements IUserToken { @Column() user_id: string; + @ManyToOne(() => User) + @JoinColumn({ name: 'user_id' }) + user: User; + @CreateDateColumn() created_at: Date; From 4460219c2a3bd44d757510bb301163ad16d8b42d Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 16:34:11 -0300 Subject: [PATCH 71/92] chore: repository fake objects --- .../fakes/ObjectsFakeRepository.ts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts diff --git a/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts b/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts new file mode 100644 index 0000000..0cc120b --- /dev/null +++ b/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts @@ -0,0 +1,51 @@ +import { ObjectLostFound } from '../../../infra/typeorm/entities/ObjectLostFound'; +import { ICreateObjectDTO } from '../../dtos/ICreateObjectDTO'; +import { IObject } from '../../models/IObject'; +import { IObjectsRepository } from '../IObjectsRepository'; + +class ObjectsFakeRepository implements IObjectsRepository { + objects: ObjectLostFound[] = []; + + async create({ + name, + comments, + type: TypeEnum, + category_id, + }: ICreateObjectDTO): Promise { + const object = new ObjectLostFound(); + + Object.assign(object, { + name, + comments, + type: TypeEnum, + category_id, + }); + + this.objects.push(object); + + return object; + } + + async findAll(): Promise { + const objects = this.objects; + + return objects; + } + + async findAvaliable(name?: string, category_id?: string): Promise { + let availableObjects = this.objects.filter(object => object.available); + + if (!name && !category_id) return availableObjects; + + availableObjects = availableObjects.filter(object => { + if (object.name === name) return true; + if (object.category_id === category_id) return true; + + return false; + }); + + return availableObjects; + } +} + +export { ObjectsFakeRepository }; From c5ece274d5ed1c45e03a4fc695e8e361946875ce Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 16:35:30 -0300 Subject: [PATCH 72/92] refactor: category delete test --- .../categories/services/tests/DeleteCategoryService.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/modules/categories/services/tests/DeleteCategoryService.spec.ts b/src/modules/categories/services/tests/DeleteCategoryService.spec.ts index 0a4db5d..370d7e2 100644 --- a/src/modules/categories/services/tests/DeleteCategoryService.spec.ts +++ b/src/modules/categories/services/tests/DeleteCategoryService.spec.ts @@ -16,8 +16,6 @@ describe('Delete Category', () => { description: 'Category Description', }); - expect(category).toHaveProperty('id'); - const deleteCategory = await categoriesFakeRepository.findByDelete( category.id, ); From 4f98b6261fb14e9fa9917b139ae95b79a98a5cb6 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 17:14:53 -0300 Subject: [PATCH 73/92] test: ensure that the listing of all objects returns 200 --- .../tests/ListAllObjectsService.spec.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/modules/objects/services/tests/ListAllObjectsService.spec.ts diff --git a/src/modules/objects/services/tests/ListAllObjectsService.spec.ts b/src/modules/objects/services/tests/ListAllObjectsService.spec.ts new file mode 100644 index 0000000..eed2460 --- /dev/null +++ b/src/modules/objects/services/tests/ListAllObjectsService.spec.ts @@ -0,0 +1,33 @@ +import { ObjectsFakeRepository } from '../../domain/repositories/fakes/ObjectsFakeRepository'; +import { CreateObjectService } from '../CreateObjectService'; +import { ListAllObjectsService } from '../ListAllObjectsService'; + +let listAllObjectsService: ListAllObjectsService; +let objectsFakeRepository: ObjectsFakeRepository; +let createObjectService: CreateObjectService; + +enum TypeEnum { + Found = 'Perdido', + Lost = 'Achado', +} + +describe('List Objetcs', () => { + beforeEach(() => { + objectsFakeRepository = new ObjectsFakeRepository(); + listAllObjectsService = new ListAllObjectsService(objectsFakeRepository); + createObjectService = new CreateObjectService(objectsFakeRepository); + }); + + it('should be able to list all objetcs', async () => { + const object = await createObjectService.execute({ + name: 'Object', + comments: 'Comments', + type: TypeEnum.Found, + category_id: 'Category', + }); + + const objetcs = await listAllObjectsService.execute(); + + expect(objetcs).toEqual([object]); + }); +}); From efa203837284221222938c84f812c215c2bdedd2 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 17:30:33 -0300 Subject: [PATCH 74/92] test: ensure that the listing of all accessible objects returns 200 --- .../tests/ListAvaliableObjectService.spec.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts diff --git a/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts b/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts new file mode 100644 index 0000000..d6dc183 --- /dev/null +++ b/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts @@ -0,0 +1,33 @@ +import { ObjectsFakeRepository } from '../../domain/repositories/fakes/ObjectsFakeRepository'; +import { CreateObjectService } from '../CreateObjectService'; +import { ListAvaliableObjectService } from '../ListAvaliableObjectService'; + +let objectsFakeRepository: ObjectsFakeRepository; +let createObjectService: CreateObjectService; +let listAvaliableObject: ListAvaliableObjectService; + +enum TypeEnum { + Found = 'Perdido', + Lost = 'Achado', +} + +describe('List Objetcs', () => { + beforeEach(() => { + objectsFakeRepository = new ObjectsFakeRepository(); + listAvaliableObject = new ListAvaliableObjectService(objectsFakeRepository); + createObjectService = new CreateObjectService(objectsFakeRepository); + }); + + it('should be able to list all available objetcs', async () => { + const objectAvailable = await createObjectService.execute({ + name: 'Object', + comments: 'Comments', + type: TypeEnum.Found, + category_id: 'category_id', + }); + + const objetcs = await listAvaliableObject.execute({}); + + expect(objetcs).toEqual([objectAvailable]); + }); +}); From 66e6b9dfa5cfc4479a2bfb1051e1630fb36f9043 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 17:36:59 -0300 Subject: [PATCH 75/92] test: ensure that listing all objects accessible by name returns 200 --- .../tests/ListAvaliableObjectService.spec.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts b/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts index d6dc183..aca1f2c 100644 --- a/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts +++ b/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts @@ -30,4 +30,19 @@ describe('List Objetcs', () => { expect(objetcs).toEqual([objectAvailable]); }); + + it('should be able to list all available objetcs by name', async () => { + const objectAvailable = await createObjectService.execute({ + name: 'Object', + comments: 'Comments', + type: TypeEnum.Found, + category_id: 'category_id', + }); + + const objetcs = await listAvaliableObject.execute({ + name: 'Object', + }); + + expect(objetcs).toEqual([objectAvailable]); + }); }); From 0d86d21035b3c33d1bd91e7cc1b51c613cdf8372 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 17:39:15 -0300 Subject: [PATCH 76/92] test: ensure that listing all objects accessible by category returns 200 --- .../tests/ListAvaliableObjectService.spec.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts b/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts index aca1f2c..0b0b7fd 100644 --- a/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts +++ b/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts @@ -45,4 +45,19 @@ describe('List Objetcs', () => { expect(objetcs).toEqual([objectAvailable]); }); + + it('should be able to list all available objetcs by category', async () => { + const objectAvailable = await createObjectService.execute({ + name: 'Object', + comments: 'Comments', + type: TypeEnum.Found, + category_id: 'category_id', + }); + + const objetcs = await listAvaliableObject.execute({ + category_id: 'category_id', + }); + + expect(objetcs).toEqual([objectAvailable]); + }); }); From 9d82b950e545350d421463b0e4343056b62d97a6 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 18:30:55 -0300 Subject: [PATCH 77/92] test: ensure that the listing of all users returns 200 --- .../services/tests/ListUserService.spec.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/modules/users/services/tests/ListUserService.spec.ts diff --git a/src/modules/users/services/tests/ListUserService.spec.ts b/src/modules/users/services/tests/ListUserService.spec.ts new file mode 100644 index 0000000..0b2c0d6 --- /dev/null +++ b/src/modules/users/services/tests/ListUserService.spec.ts @@ -0,0 +1,33 @@ +import { UsersFakeRepository } from '../../domain/repositories/fakes/UsersFakeRepository'; +import { HashProviderFakeRepository } from '../../providers/fakes/HashProviderFakeRepository'; +import { CreateUserService } from '../CreateUserService'; +import { ListUserService } from '../ListUserService'; + +let listUserService: ListUserService; +let createUserService: CreateUserService; +let usersFakeRepository: UsersFakeRepository; +let hashProviderFakeRepository: HashProviderFakeRepository; + +describe('List Users', () => { + beforeEach(() => { + usersFakeRepository = new UsersFakeRepository(); + hashProviderFakeRepository = new HashProviderFakeRepository(); + createUserService = new CreateUserService( + usersFakeRepository, + hashProviderFakeRepository, + ); + listUserService = new ListUserService(usersFakeRepository); + }); + + it('should be able to list all users', async () => { + const user = await createUserService.execute({ + name: 'Nome Test', + email: 'test@test.com', + password: '123456', + }); + + const users = await listUserService.execute(); + + expect(users).toEqual([user]); + }); +}); From ee76205c604ba41e5c50eff6b87441a8c6871383 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Sat, 22 Jan 2022 18:43:13 -0300 Subject: [PATCH 78/92] test: ensure the user is deleted --- .../services/tests/DeleteUserService.spec.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/modules/users/services/tests/DeleteUserService.spec.ts diff --git a/src/modules/users/services/tests/DeleteUserService.spec.ts b/src/modules/users/services/tests/DeleteUserService.spec.ts new file mode 100644 index 0000000..a1d702c --- /dev/null +++ b/src/modules/users/services/tests/DeleteUserService.spec.ts @@ -0,0 +1,30 @@ +import { UsersFakeRepository } from '../../domain/repositories/fakes/UsersFakeRepository'; +import { HashProviderFakeRepository } from '../../providers/fakes/HashProviderFakeRepository'; +import { CreateUserService } from '../CreateUserService'; + +let createUserService: CreateUserService; +let hashProviderFakeRepository: HashProviderFakeRepository; +let usersFakeRepository: UsersFakeRepository; + +describe('Delete User', () => { + beforeEach(() => { + usersFakeRepository = new UsersFakeRepository(); + hashProviderFakeRepository = new HashProviderFakeRepository(); + createUserService = new CreateUserService( + usersFakeRepository, + hashProviderFakeRepository, + ); + }); + + it('should be able to delete a user', async () => { + const user = await createUserService.execute({ + name: 'Nome Test', + email: 'test@test.com', + password: '123456', + }); + + const deleteUser = await usersFakeRepository.findByDelete(user.id); + + expect(deleteUser).toBeUndefined(); + }); +}); From 09f571a43f75b3e91476ae3ba068717bf90ff231 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Mon, 24 Jan 2022 19:50:48 -0300 Subject: [PATCH 79/92] chore: adding migration messages --- .../migrations/1643045173629-CreateMessage.ts | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/shared/infra/typeorm/migrations/1643045173629-CreateMessage.ts diff --git a/src/shared/infra/typeorm/migrations/1643045173629-CreateMessage.ts b/src/shared/infra/typeorm/migrations/1643045173629-CreateMessage.ts new file mode 100644 index 0000000..08bf7bf --- /dev/null +++ b/src/shared/infra/typeorm/migrations/1643045173629-CreateMessage.ts @@ -0,0 +1,62 @@ +import { MigrationInterface, QueryRunner, Table } from 'typeorm'; + +export class CreateMessage1643045173629 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.createTable( + new Table({ + name: 'messages', + columns: [ + { + name: 'id', + type: 'uuid', + isPrimary: true, + }, + { + name: 'user_id', + type: 'uuid', + }, + { + name: 'object_id', + type: 'uuid', + }, + { + name: 'message', + type: 'varchar', + }, + { + name: 'created_at', + type: 'timestamp', + default: 'now()', + }, + { + name: 'updated_at', + type: 'timestamp', + default: 'now()', + }, + ], + foreignKeys: [ + { + name: 'FKUserMessage', + referencedTableName: 'users', + referencedColumnNames: ['id'], + columnNames: ['user_id'], + onDelete: 'SET NULL', + onUpdate: 'SET NULL', + }, + { + name: 'FKObjectMessage', + referencedTableName: 'objects', + referencedColumnNames: ['id'], + columnNames: ['object_id'], + onDelete: 'SET NULL', + onUpdate: 'SET NULL', + }, + ], + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropTable('messages'); + } +} From fd00af4f0cfb566d41c4dc9f0ae4518790f50438 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Mon, 24 Jan 2022 19:51:54 -0300 Subject: [PATCH 80/92] feat: object messages --- .../objects/domain/models/IObjectMessage.ts | 13 ++++++ .../IObjectsMessagesRepository.ts | 17 +++++++ .../domain/repositories/IObjectsRepository.ts | 1 + .../CreateObjectMessageController.ts | 21 +++++++++ .../infra/http/routes/objects.routes.ts | 10 +++++ .../infra/typeorm/entities/ObjectMessage.ts | 44 +++++++++++++++++++ .../repositories/ObjectsMessagesRepository.ts | 33 ++++++++++++++ .../services/CreateObjectMessageService.ts | 33 ++++++++++++++ src/shared/container/index.ts | 7 +++ 9 files changed, 179 insertions(+) create mode 100644 src/modules/objects/domain/models/IObjectMessage.ts create mode 100644 src/modules/objects/domain/repositories/IObjectsMessagesRepository.ts create mode 100644 src/modules/objects/infra/http/controllers/CreateObjectMessageController.ts create mode 100644 src/modules/objects/infra/typeorm/entities/ObjectMessage.ts create mode 100644 src/modules/objects/infra/typeorm/repositories/ObjectsMessagesRepository.ts create mode 100644 src/modules/objects/services/CreateObjectMessageService.ts diff --git a/src/modules/objects/domain/models/IObjectMessage.ts b/src/modules/objects/domain/models/IObjectMessage.ts new file mode 100644 index 0000000..be785b2 --- /dev/null +++ b/src/modules/objects/domain/models/IObjectMessage.ts @@ -0,0 +1,13 @@ +import { User } from '@modules/users/infra/typeorm/entities/User'; + +interface IObjectMessage { + id: string; + user_id: string; + object_id: string; + user: User; + message: string; + created_at: Date; + updated_at: Date; +} + +export { IObjectMessage }; diff --git a/src/modules/objects/domain/repositories/IObjectsMessagesRepository.ts b/src/modules/objects/domain/repositories/IObjectsMessagesRepository.ts new file mode 100644 index 0000000..4f26ef3 --- /dev/null +++ b/src/modules/objects/domain/repositories/IObjectsMessagesRepository.ts @@ -0,0 +1,17 @@ +import { IObjectMessage } from '../models/IObjectMessage'; + +interface ICreateObjectMessageDTO { + user_id: string; + object_id: string; + message: string; +} + +interface IObjectsMessagesRepository { + create({ + user_id, + object_id, + message, + }: ICreateObjectMessageDTO): Promise; +} + +export { IObjectsMessagesRepository, ICreateObjectMessageDTO }; diff --git a/src/modules/objects/domain/repositories/IObjectsRepository.ts b/src/modules/objects/domain/repositories/IObjectsRepository.ts index d36aab0..8f66695 100644 --- a/src/modules/objects/domain/repositories/IObjectsRepository.ts +++ b/src/modules/objects/domain/repositories/IObjectsRepository.ts @@ -5,6 +5,7 @@ interface IObjectsRepository { create(data: ICreateObjectDTO): Promise; findAll(): Promise; findAvaliable(name?: string, category_id?: string): Promise; + findById(id: string): Promise; } export { IObjectsRepository }; diff --git a/src/modules/objects/infra/http/controllers/CreateObjectMessageController.ts b/src/modules/objects/infra/http/controllers/CreateObjectMessageController.ts new file mode 100644 index 0000000..db0c51e --- /dev/null +++ b/src/modules/objects/infra/http/controllers/CreateObjectMessageController.ts @@ -0,0 +1,21 @@ +import { CreateObjectMessageService } from '@modules/objects/services/CreateObjectMessageService'; +import { Request, Response } from 'express'; +import { container } from 'tsyringe'; + +class CreateObjectMessageController { + async handle(request: Request, response: Response): Promise { + const { user_id, object_id, message } = request.body; + + const createObjectMessage = container.resolve(CreateObjectMessageService); + + const createMessage = await createObjectMessage.execute({ + user_id, + object_id, + message, + }); + + return response.status(201).json(createMessage); + } +} + +export { CreateObjectMessageController }; diff --git a/src/modules/objects/infra/http/routes/objects.routes.ts b/src/modules/objects/infra/http/routes/objects.routes.ts index 40b1a61..43d1ac8 100644 --- a/src/modules/objects/infra/http/routes/objects.routes.ts +++ b/src/modules/objects/infra/http/routes/objects.routes.ts @@ -7,6 +7,8 @@ import { UploadObjectImageController } from '../controllers/UploadObjectImageCon import uploadConfig from '@config/upload'; import { ListAvaliableObjectController } from '../controllers/ListAvaliableObjectController'; import { celebrate, Joi, Segments } from 'celebrate'; +import { CreateObjectMessageController } from '../controllers/CreateObjectMessageController'; +import ensureAdmin from '@shared/infra/http/middlewares/ensureAdmin'; const objectsRoutes = Router(); @@ -14,6 +16,7 @@ const createObjectController = new CreateObjectController(); const listAllObjectsController = new ListAllObjectsController(); const uploadObjectImageController = new UploadObjectImageController(); const listAvaliableObjectController = new ListAvaliableObjectController(); +const createObjectMessageController = new CreateObjectMessageController(); const uploadImages = multer(uploadConfig); @@ -42,4 +45,11 @@ objectsRoutes.post( uploadObjectImageController.handle, ); +objectsRoutes.post( + '/message', + ensureAuthenticated, + ensureAdmin, + createObjectMessageController.handle, +); + export { objectsRoutes }; diff --git a/src/modules/objects/infra/typeorm/entities/ObjectMessage.ts b/src/modules/objects/infra/typeorm/entities/ObjectMessage.ts new file mode 100644 index 0000000..c521a26 --- /dev/null +++ b/src/modules/objects/infra/typeorm/entities/ObjectMessage.ts @@ -0,0 +1,44 @@ +import { IObjectMessage } from '@modules/objects/domain/models/IObjectMessage'; +import { User } from '@modules/users/infra/typeorm/entities/User'; +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + PrimaryColumn, +} from 'typeorm'; +import { v4 as uuidV4 } from 'uuid'; + +@Entity('messages') +class ObjectMessage implements IObjectMessage { + @PrimaryColumn() + id: string; + + @Column() + user_id: string; + + @Column() + object_id: string; + + @ManyToOne(() => User) + @JoinColumn({ name: 'user_id' }) + user: User; + + @Column() + message: string; + + @CreateDateColumn() + created_at: Date; + + @CreateDateColumn() + updated_at: Date; + + constructor() { + if (!this.id) { + this.id = uuidV4(); + } + } +} + +export { ObjectMessage }; diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsMessagesRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsMessagesRepository.ts new file mode 100644 index 0000000..9429b80 --- /dev/null +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsMessagesRepository.ts @@ -0,0 +1,33 @@ +import { IObjectMessage } from '@modules/objects/domain/models/IObjectMessage'; +import { + ICreateObjectMessageDTO, + IObjectsMessagesRepository, +} from '@modules/objects/domain/repositories/IObjectsMessagesRepository'; +import { getRepository, Repository } from 'typeorm'; +import { ObjectMessage } from '../entities/ObjectMessage'; + +class ObjectsMessagesRepository implements IObjectsMessagesRepository { + private repository: Repository; + + constructor() { + this.repository = getRepository(ObjectMessage); + } + + async create({ + user_id, + object_id, + message, + }: ICreateObjectMessageDTO): Promise { + const objectMessage = this.repository.create({ + user_id, + object_id, + message, + }); + + await this.repository.save(objectMessage); + + return objectMessage; + } +} + +export { ObjectsMessagesRepository }; diff --git a/src/modules/objects/services/CreateObjectMessageService.ts b/src/modules/objects/services/CreateObjectMessageService.ts new file mode 100644 index 0000000..60990f5 --- /dev/null +++ b/src/modules/objects/services/CreateObjectMessageService.ts @@ -0,0 +1,33 @@ +import { IUsersRepository } from '@modules/users/domain/repositories/IUsersRepository'; +import { AppError } from '@shared/errors/AppError'; +import { inject, injectable } from 'tsyringe'; +import { IObjectMessage } from '../domain/models/IObjectMessage'; +import { + ICreateObjectMessageDTO, + IObjectsMessagesRepository, +} from '../domain/repositories/IObjectsMessagesRepository'; +import { IObjectsRepository } from '../domain/repositories/IObjectsRepository'; + +@injectable() +class CreateObjectMessageService { + constructor( + @inject('ObjectsMessagesRepository') + private objectsMessagesRepository: IObjectsMessagesRepository, + ) {} + + async execute({ + user_id, + object_id, + message, + }: ICreateObjectMessageDTO): Promise { + const objectMessage = await this.objectsMessagesRepository.create({ + user_id, + object_id, + message, + }); + + return objectMessage; + } +} + +export { CreateObjectMessageService }; diff --git a/src/shared/container/index.ts b/src/shared/container/index.ts index 8c333fc..f4efd7e 100644 --- a/src/shared/container/index.ts +++ b/src/shared/container/index.ts @@ -12,6 +12,8 @@ import { IObjectsRepository } from '@modules/objects/domain/repositories/IObject import { ObjectsRepository } from '@modules/objects/infra/typeorm/repositories/ObjectsRepository'; import { IObjectsImagesRepository } from '@modules/objects/domain/repositories/IObjectsImagesRepository'; import { ObjectsImagesRepository } from '@modules/objects/infra/typeorm/repositories/ObjectsImagesRepository'; +import { ObjectsMessagesRepository } from '@modules/objects/infra/typeorm/repositories/ObjectsMessagesRepository'; +import { IObjectsMessagesRepository } from '@modules/objects/domain/repositories/IObjectsMessagesRepository'; container.registerSingleton( 'UsersRepository', @@ -37,3 +39,8 @@ container.registerSingleton( 'ObjectsImagesRepository', ObjectsImagesRepository, ); + +container.registerSingleton( + 'ObjectsMessagesRepository', + ObjectsMessagesRepository, +); From 3eebf6457f2c7e047ca4a983f4bd276b652ac9b7 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Mon, 24 Jan 2022 19:52:49 -0300 Subject: [PATCH 81/92] chore: implementation of a findbyid in objscts --- .../objects/infra/typeorm/repositories/ObjectsRepository.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts index 3189d11..11da5df 100644 --- a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts @@ -11,6 +11,12 @@ class ObjectsRepository implements IObjectsRepository { this.repository = getRepository(ObjectLostFound); } + async findById(id: string): Promise { + const object = await this.repository.findOne(id); + + return object; + } + async findAvaliable(name?: string, category_id?: string): Promise { const objectsQuery = await this.repository .createQueryBuilder('c') From 889b9c9916ad976ddcb2605c3beca62ccc110f6e Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Mon, 24 Jan 2022 23:34:08 -0300 Subject: [PATCH 82/92] refactor: adding attributes and making entity relationship --- .../objects/domain/dtos/ICreateObjectDTO.ts | 1 + src/modules/objects/domain/models/IObject.ts | 3 ++ .../controllers/CreateObjectController.ts | 2 ++ .../infra/typeorm/entities/ObjectLostFound.ts | 8 +++++ .../typeorm/repositories/ObjectsRepository.ts | 2 ++ .../services/CreateObjectMessageService.ts | 9 ++++- .../objects/services/CreateObjectService.ts | 2 ++ .../users/infra/typeorm/entities/User.ts | 5 +++ .../1643070334064-AddUserIdToObjects.ts | 36 +++++++++++++++++++ 9 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/shared/infra/typeorm/migrations/1643070334064-AddUserIdToObjects.ts diff --git a/src/modules/objects/domain/dtos/ICreateObjectDTO.ts b/src/modules/objects/domain/dtos/ICreateObjectDTO.ts index 7543a64..ffea56b 100644 --- a/src/modules/objects/domain/dtos/ICreateObjectDTO.ts +++ b/src/modules/objects/domain/dtos/ICreateObjectDTO.ts @@ -4,6 +4,7 @@ interface ICreateObjectDTO { name: string; comments: string; type: TypeEnum; + user_id: string; category_id: string; } diff --git a/src/modules/objects/domain/models/IObject.ts b/src/modules/objects/domain/models/IObject.ts index 68d7786..e2d3038 100644 --- a/src/modules/objects/domain/models/IObject.ts +++ b/src/modules/objects/domain/models/IObject.ts @@ -1,5 +1,6 @@ import { Category } from '@modules/categories/infra/typeorm/entities/Category'; import { TypeEnum } from '@modules/objects/infra/typeorm/entities/TypeEnum'; +import { User } from '@modules/users/infra/typeorm/entities/User'; interface IObject { id: string; @@ -9,6 +10,8 @@ interface IObject { type: TypeEnum; category_id: string; category: Category; + user_id: string; + user: User; created_at: Date; updated_at: Date; } diff --git a/src/modules/objects/infra/http/controllers/CreateObjectController.ts b/src/modules/objects/infra/http/controllers/CreateObjectController.ts index 24e54f0..65ec187 100644 --- a/src/modules/objects/infra/http/controllers/CreateObjectController.ts +++ b/src/modules/objects/infra/http/controllers/CreateObjectController.ts @@ -4,6 +4,7 @@ import { container } from 'tsyringe'; class CreateObjectController { async handle(request: Request, response: Response): Promise { + const { id } = request.user; const { name, comments, type, category_id } = request.body; const createObjectService = container.resolve(CreateObjectService); @@ -12,6 +13,7 @@ class CreateObjectController { name, comments, type, + user_id: id, category_id, }); diff --git a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts index 941fb09..5a117a0 100644 --- a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts +++ b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts @@ -13,6 +13,7 @@ import { import { v4 as uuidV4 } from 'uuid'; import { TypeEnum } from './TypeEnum'; +import { User } from '@modules/users/infra/typeorm/entities/User'; @Entity('objects') class ObjectLostFound implements IObject { @@ -38,6 +39,13 @@ class ObjectLostFound implements IObject { @JoinColumn({ name: 'category_id' }) category: Category; + @Column() + user_id: string; + + @ManyToOne(() => User, user => user.object_lost_found) + @JoinColumn({ name: 'user_id' }) + user: User; + @CreateDateColumn() created_at: Date; diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts index 11da5df..8cef30a 100644 --- a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts @@ -45,12 +45,14 @@ class ObjectsRepository implements IObjectsRepository { name, comments, type, + user_id, category_id, }: ICreateObjectDTO): Promise { const object = this.repository.create({ name, comments, type, + user_id, category_id, }); diff --git a/src/modules/objects/services/CreateObjectMessageService.ts b/src/modules/objects/services/CreateObjectMessageService.ts index 60990f5..c338d8d 100644 --- a/src/modules/objects/services/CreateObjectMessageService.ts +++ b/src/modules/objects/services/CreateObjectMessageService.ts @@ -1,4 +1,3 @@ -import { IUsersRepository } from '@modules/users/domain/repositories/IUsersRepository'; import { AppError } from '@shared/errors/AppError'; import { inject, injectable } from 'tsyringe'; import { IObjectMessage } from '../domain/models/IObjectMessage'; @@ -11,6 +10,8 @@ import { IObjectsRepository } from '../domain/repositories/IObjectsRepository'; @injectable() class CreateObjectMessageService { constructor( + @inject('ObjectsRepository') + private objectsRepository: IObjectsRepository, @inject('ObjectsMessagesRepository') private objectsMessagesRepository: IObjectsMessagesRepository, ) {} @@ -20,6 +21,12 @@ class CreateObjectMessageService { object_id, message, }: ICreateObjectMessageDTO): Promise { + const object = await this.objectsRepository.findById(object_id); + + if (!object) { + throw new AppError('Object not found', 404); + } + const objectMessage = await this.objectsMessagesRepository.create({ user_id, object_id, diff --git a/src/modules/objects/services/CreateObjectService.ts b/src/modules/objects/services/CreateObjectService.ts index d64e5df..bc469ca 100644 --- a/src/modules/objects/services/CreateObjectService.ts +++ b/src/modules/objects/services/CreateObjectService.ts @@ -14,12 +14,14 @@ class CreateObjectService { name, comments, type, + user_id, category_id, }: ICreateObjectDTO): Promise { const object = this.objectsRepository.create({ name, comments, type, + user_id, category_id, }); diff --git a/src/modules/users/infra/typeorm/entities/User.ts b/src/modules/users/infra/typeorm/entities/User.ts index e342a24..a0580f0 100644 --- a/src/modules/users/infra/typeorm/entities/User.ts +++ b/src/modules/users/infra/typeorm/entities/User.ts @@ -3,12 +3,14 @@ import { Column, CreateDateColumn, Entity, + OneToMany, PrimaryColumn, UpdateDateColumn, } from 'typeorm'; import { Exclude } from 'class-transformer'; import { v4 as uuidV4 } from 'uuid'; +import { ObjectLostFound } from '@modules/objects/infra/typeorm/entities/ObjectLostFound'; @Entity('users') class User implements IUser { @@ -31,6 +33,9 @@ class User implements IUser { @Column() isAdmin: boolean; + @OneToMany(() => ObjectLostFound, object_lost_found => object_lost_found.user) + object_lost_found: ObjectLostFound[]; + @CreateDateColumn() created_at: Date; diff --git a/src/shared/infra/typeorm/migrations/1643070334064-AddUserIdToObjects.ts b/src/shared/infra/typeorm/migrations/1643070334064-AddUserIdToObjects.ts new file mode 100644 index 0000000..d710dd2 --- /dev/null +++ b/src/shared/infra/typeorm/migrations/1643070334064-AddUserIdToObjects.ts @@ -0,0 +1,36 @@ +import { + MigrationInterface, + QueryRunner, + TableColumn, + TableForeignKey, +} from 'typeorm'; + +export class AddUserIdToObjects1643070334064 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.addColumn( + 'objects', + new TableColumn({ + name: 'user_id', + type: 'uuid', + isNullable: true, + }), + ); + + await queryRunner.createForeignKey( + 'objects', + new TableForeignKey({ + name: 'FKUserObjects', + columnNames: ['user_id'], + referencedTableName: 'users', + referencedColumnNames: ['id'], + onDelete: 'SET NULL', + onUpdate: 'SET NULL', + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropForeignKey('objects', 'FKUserObejects'); + await queryRunner.dropColumn('objects', 'user_id'); + } +} From 39edf3cfedc1bbf801d237716adac872a63b954a Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 25 Jan 2022 03:20:34 -0300 Subject: [PATCH 83/92] fix: bug tests --- .../domain/repositories/fakes/ObjectsFakeRepository.ts | 8 ++++++++ .../objects/infra/typeorm/entities/ObjectLostFound.ts | 2 +- .../objects/services/tests/CreateObjectService.spec.ts | 1 + .../objects/services/tests/ListAllObjectsService.spec.ts | 1 + .../services/tests/ListAvaliableObjectService.spec.ts | 3 +++ src/modules/users/domain/models/IUser.ts | 3 +++ src/modules/users/infra/typeorm/entities/User.ts | 2 +- 7 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts b/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts index 0cc120b..1ed5915 100644 --- a/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts +++ b/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts @@ -10,6 +10,7 @@ class ObjectsFakeRepository implements IObjectsRepository { name, comments, type: TypeEnum, + user_id, category_id, }: ICreateObjectDTO): Promise { const object = new ObjectLostFound(); @@ -18,6 +19,7 @@ class ObjectsFakeRepository implements IObjectsRepository { name, comments, type: TypeEnum, + user_id, category_id, }); @@ -46,6 +48,12 @@ class ObjectsFakeRepository implements IObjectsRepository { return availableObjects; } + + async findById(id: string): Promise { + const objects = this.objects.find(object => object.id === id); + + return objects; + } } export { ObjectsFakeRepository }; diff --git a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts index 5a117a0..0db9ada 100644 --- a/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts +++ b/src/modules/objects/infra/typeorm/entities/ObjectLostFound.ts @@ -13,7 +13,7 @@ import { import { v4 as uuidV4 } from 'uuid'; import { TypeEnum } from './TypeEnum'; -import { User } from '@modules/users/infra/typeorm/entities/User'; +import { User } from '../../../../users/infra/typeorm/entities/User'; @Entity('objects') class ObjectLostFound implements IObject { diff --git a/src/modules/objects/services/tests/CreateObjectService.spec.ts b/src/modules/objects/services/tests/CreateObjectService.spec.ts index 4b7c008..e473856 100644 --- a/src/modules/objects/services/tests/CreateObjectService.spec.ts +++ b/src/modules/objects/services/tests/CreateObjectService.spec.ts @@ -20,6 +20,7 @@ describe('Create Object', () => { name: 'Object', comments: 'Comments', type: TypeEnum.Found, + user_id: 'user_id', category_id: 'Category', }); diff --git a/src/modules/objects/services/tests/ListAllObjectsService.spec.ts b/src/modules/objects/services/tests/ListAllObjectsService.spec.ts index eed2460..1ea74f2 100644 --- a/src/modules/objects/services/tests/ListAllObjectsService.spec.ts +++ b/src/modules/objects/services/tests/ListAllObjectsService.spec.ts @@ -23,6 +23,7 @@ describe('List Objetcs', () => { name: 'Object', comments: 'Comments', type: TypeEnum.Found, + user_id: 'user_id', category_id: 'Category', }); diff --git a/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts b/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts index 0b0b7fd..068dd8f 100644 --- a/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts +++ b/src/modules/objects/services/tests/ListAvaliableObjectService.spec.ts @@ -23,6 +23,7 @@ describe('List Objetcs', () => { name: 'Object', comments: 'Comments', type: TypeEnum.Found, + user_id: 'user_id', category_id: 'category_id', }); @@ -36,6 +37,7 @@ describe('List Objetcs', () => { name: 'Object', comments: 'Comments', type: TypeEnum.Found, + user_id: 'user_id', category_id: 'category_id', }); @@ -51,6 +53,7 @@ describe('List Objetcs', () => { name: 'Object', comments: 'Comments', type: TypeEnum.Found, + user_id: 'user_id', category_id: 'category_id', }); diff --git a/src/modules/users/domain/models/IUser.ts b/src/modules/users/domain/models/IUser.ts index ab13261..14b494d 100644 --- a/src/modules/users/domain/models/IUser.ts +++ b/src/modules/users/domain/models/IUser.ts @@ -1,9 +1,12 @@ +import { ObjectLostFound } from '@modules/objects/infra/typeorm/entities/ObjectLostFound'; + interface IUser { id: string; name: string; email: string; password: string; avatar: string; + object_lost_found: ObjectLostFound[]; isAdmin: boolean; created_at: Date; updated_at: Date; diff --git a/src/modules/users/infra/typeorm/entities/User.ts b/src/modules/users/infra/typeorm/entities/User.ts index a0580f0..cdf9ac4 100644 --- a/src/modules/users/infra/typeorm/entities/User.ts +++ b/src/modules/users/infra/typeorm/entities/User.ts @@ -10,7 +10,7 @@ import { import { Exclude } from 'class-transformer'; import { v4 as uuidV4 } from 'uuid'; -import { ObjectLostFound } from '@modules/objects/infra/typeorm/entities/ObjectLostFound'; +import { ObjectLostFound } from '../../../../objects/infra/typeorm/entities/ObjectLostFound'; @Entity('users') class User implements IUser { From 83e585e3263b7b5d9bab92f59b77f22c6a854e22 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 25 Jan 2022 12:53:35 -0300 Subject: [PATCH 84/92] feat: adding column in users table --- .../users/domain/dtos/ICreateUserDTO.ts | 1 + src/modules/users/domain/models/IUser.ts | 1 + .../http/controllers/CreateUserController.ts | 3 ++- .../users/infra/http/routes/users.routes.ts | 1 + .../users/infra/typeorm/entities/User.ts | 3 +++ .../typeorm/repositories/UsersRepository.ts | 8 +++++++- .../users/services/CreateUserService.ts | 8 +++++++- .../1643123925936-AddDataInUserTable.ts | 18 ++++++++++++++++++ 8 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/shared/infra/typeorm/migrations/1643123925936-AddDataInUserTable.ts diff --git a/src/modules/users/domain/dtos/ICreateUserDTO.ts b/src/modules/users/domain/dtos/ICreateUserDTO.ts index f90fbd3..cbab1cf 100644 --- a/src/modules/users/domain/dtos/ICreateUserDTO.ts +++ b/src/modules/users/domain/dtos/ICreateUserDTO.ts @@ -2,6 +2,7 @@ interface ICreateUserDTO { name: string; email: string; password: string; + telephone: string; } export { ICreateUserDTO }; diff --git a/src/modules/users/domain/models/IUser.ts b/src/modules/users/domain/models/IUser.ts index 14b494d..175a097 100644 --- a/src/modules/users/domain/models/IUser.ts +++ b/src/modules/users/domain/models/IUser.ts @@ -6,6 +6,7 @@ interface IUser { email: string; password: string; avatar: string; + telephone: string; object_lost_found: ObjectLostFound[]; isAdmin: boolean; created_at: Date; diff --git a/src/modules/users/infra/http/controllers/CreateUserController.ts b/src/modules/users/infra/http/controllers/CreateUserController.ts index bf6d791..4c00770 100644 --- a/src/modules/users/infra/http/controllers/CreateUserController.ts +++ b/src/modules/users/infra/http/controllers/CreateUserController.ts @@ -5,13 +5,14 @@ import { container } from 'tsyringe'; class CreateUserController { async handle(request: Request, response: Response): Promise { - const { name, email, password } = request.body; + const { name, email, telephone, password } = request.body; const createUserService = container.resolve(CreateUserService); const createUser = await createUserService.execute({ name, email, + telephone, password, }); diff --git a/src/modules/users/infra/http/routes/users.routes.ts b/src/modules/users/infra/http/routes/users.routes.ts index 1c3688f..7b4a9d3 100644 --- a/src/modules/users/infra/http/routes/users.routes.ts +++ b/src/modules/users/infra/http/routes/users.routes.ts @@ -29,6 +29,7 @@ usersRoutes.post( [Segments.BODY]: { name: Joi.string().required(), email: Joi.string().required().email(), + telephone: Joi.string().required(), password: Joi.string().required().min(6).max(18), }, }), diff --git a/src/modules/users/infra/typeorm/entities/User.ts b/src/modules/users/infra/typeorm/entities/User.ts index cdf9ac4..461cd94 100644 --- a/src/modules/users/infra/typeorm/entities/User.ts +++ b/src/modules/users/infra/typeorm/entities/User.ts @@ -30,6 +30,9 @@ class User implements IUser { @Column() avatar: string; + @Column() + telephone: string; + @Column() isAdmin: boolean; diff --git a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts index fd5d09c..3e05996 100644 --- a/src/modules/users/infra/typeorm/repositories/UsersRepository.ts +++ b/src/modules/users/infra/typeorm/repositories/UsersRepository.ts @@ -27,10 +27,16 @@ class UsersRepository implements IUsersRepository { return users; } - async create({ name, email, password }: ICreateUserDTO): Promise { + async create({ + name, + email, + telephone, + password, + }: ICreateUserDTO): Promise { const createUser = this.repository.create({ name, email, + telephone, password, }); diff --git a/src/modules/users/services/CreateUserService.ts b/src/modules/users/services/CreateUserService.ts index 42ee45e..183190b 100644 --- a/src/modules/users/services/CreateUserService.ts +++ b/src/modules/users/services/CreateUserService.ts @@ -14,7 +14,12 @@ class CreateUserService { private hashProvider: IHashProvider, ) {} - async execute({ name, email, password }: ICreateUserDTO): Promise { + async execute({ + name, + email, + telephone, + password, + }: ICreateUserDTO): Promise { const emailExists = await this.usersRepository.findByEmail(email); if (emailExists) { @@ -26,6 +31,7 @@ class CreateUserService { const user = await this.usersRepository.create({ name, email, + telephone, password: hashdPassword, }); diff --git a/src/shared/infra/typeorm/migrations/1643123925936-AddDataInUserTable.ts b/src/shared/infra/typeorm/migrations/1643123925936-AddDataInUserTable.ts new file mode 100644 index 0000000..eec4717 --- /dev/null +++ b/src/shared/infra/typeorm/migrations/1643123925936-AddDataInUserTable.ts @@ -0,0 +1,18 @@ +import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; + +export class AddDataInUserTable1643123925936 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.addColumn( + 'users', + new TableColumn({ + name: 'telephone', + type: 'decimal', + isNullable: true, + }), + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropColumn('users', 'telephone'); + } +} From d28e530210625e3373834b823bb86bec6d3c7aec Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 25 Jan 2022 12:54:00 -0300 Subject: [PATCH 85/92] chore: readme.md --- README.md | 49 +++++++++++++++---------------------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 5209c88..6bde559 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,29 @@ -## Accurate Software +## Objetivo Geral -drawing +- Desenvolver um software para realizar o gerenciamento de objetos achados e perdidos. -Seja bem-vindo a [Accurate Software](https://accurate.com.br). +## Funcionalidades do Sistema -Temos diversas vagas para desenvolvedores: Frontend, Backend e Fullstack! +- Deve ser possível usuário se cadastrar, ler, atualizar e deletar seus dados pessoais. Visando também o controle sobre sua conta. Os usuários são dividios em usuários comuns com funcionalidades restritas para seu cadastro e usuário admnistrador com acesso a todas as funcionalidades do sistema. Os usuários comuns não poderam excluir suas contas. -> Para conhecer melhor os candidatos, preparamos um desafio técnico. Não se preocupe em cumprir todos os requisitos propostos no desafio, este teste visa avaliar a sua capacidade de resolução de problemas. Abaixo serão apresentados dois desafios direcionados aos perfis frontend e backend, caso o seu perfil for voltado para fullstack fique a vontade em nos enviar uma solução completa abordando tanto frontend quanto backend! +- Deve ser possível que usuário faça upload do seu avatar de usuário. -## Instruções +- Deve ser possível que usuário faça a recuperação de senha informando o email que será enviado um token de autorização. -1. Para começar o desafio, realize um fork no repositório: https://github.com/accurate-software/accurate-software.github.io +- Deve ser possível que usuário logado faça a troca de senha. -2. O desafio deverá set commitado no fork. +- Deve ser possível que usuário administrador cadastre, exclua, atualiza e liste categorias de objetos. -3. Após a finalização do desafio, solicite um pull request do fork no nosso repositório ;) +- Deve ser possível que usuário administrador liste todos os usuários cadastrados. -### Desafio Frontend +- Deve ser possível que o usuário, desde que logado no sistema, cadastrar um objeto perdido e/ou encontrado. O usuário administrador tem acesso pleno aos objetos criados por outros usuários. -O seu desafio é realizar um desenvolvimento de uma aplicação frontend que compra os requisitos: +- Deve ser possível que o usuário faça upload de fotos dos objetos perdidos e/ou encontrados. -+ Consumo de API REST -+ CRUD ou listagem de algum recurso da API -+ Utilizar alguma API pública, podendo ser alguma do site: https://public-apis.xyz/ +- Deve ser possível que o usuário filtre objetos disponíveis por categorias e nome. -Vamos avaliar a sua capacidade como desenvolvedor frontend, observando os critérios: +- Deve ser possível que o usuário administrador envie uma mensagem ao usuário que criou o objeto perdido, avisando-o que o objeto foi encontrado. O dono pode se dirigir ao setor responsável para retirá-lo. -+ Uso semântico do HTML -+ Estruturação do layout e tags CSS -+ Layout acessível e responsivo -+ Utilização de frameworks da atualizade, como: React, Vue, Angular ou algum outro de sua preferência. -+ Lembre-se de documentar a solução com um README.MD :) +- Deve ser possível a listagem de todos os objetos, antes de fazer o cadastro de usuário. -### Desafio Backend - -O seu desafio é realizar um desenvolvimento de uma API Rest para um site de achados e perfidos. Sua API deve conter as seguintes funcionalidades: - -+ Cadastro de um "Achado"/"Perdido" -+ Atualização de histórico de um "Achado"/"Perdido" -+ Busca com opção de filtros, como por exemplo: Categoria -+ Relatório de cruzamento de informações "Achados"/"Perdidos", dado um categoria e um raio. - -Fique a vontade para usar a linguagem e framework de sua preferência, como: Java, C# e Node! Porém se atente aos seguintes pontos: - -+ Tratamento de erros e exceções -+ Clareza e clean code no desenvolvimento da solução -+ Documentação da solução - README.MD :) +## Ferramentas e Tecnologias Utilizadas From e8af379b4d7036e99a24ad7dc1fae1fa4ea4f691 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 25 Jan 2022 13:55:55 -0300 Subject: [PATCH 86/92] feat: object will be unavailable when admin message is sent --- README.md | 4 ++-- .../objects/domain/repositories/IObjectsRepository.ts | 1 + .../domain/repositories/fakes/ObjectsFakeRepository.ts | 6 ++++++ .../infra/typeorm/repositories/ObjectsRepository.ts | 10 ++++++++++ .../objects/services/CreateObjectMessageService.ts | 2 ++ 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6bde559..7c60784 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ - Deve ser possível que o usuário faça upload de fotos dos objetos perdidos e/ou encontrados. -- Deve ser possível que o usuário filtre objetos disponíveis por categorias e nome. +- Deve ser possível que o usuário filtre todos os objetos disponíveis por categorias e nome. -- Deve ser possível que o usuário administrador envie uma mensagem ao usuário que criou o objeto perdido, avisando-o que o objeto foi encontrado. O dono pode se dirigir ao setor responsável para retirá-lo. +- Deve ser possível que o usuário administrador envie uma mensagem ao usuário que criou o objeto perdido, avisando-o que o objeto foi encontrado, com isso o objeto fica indisponível automaticamente. O dono pode se dirigir ao setor responsável para retirá-lo. - Deve ser possível a listagem de todos os objetos, antes de fazer o cadastro de usuário. diff --git a/src/modules/objects/domain/repositories/IObjectsRepository.ts b/src/modules/objects/domain/repositories/IObjectsRepository.ts index 8f66695..6b8629a 100644 --- a/src/modules/objects/domain/repositories/IObjectsRepository.ts +++ b/src/modules/objects/domain/repositories/IObjectsRepository.ts @@ -6,6 +6,7 @@ interface IObjectsRepository { findAll(): Promise; findAvaliable(name?: string, category_id?: string): Promise; findById(id: string): Promise; + updateAvailable(id: string, available: boolean): Promise; } export { IObjectsRepository }; diff --git a/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts b/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts index 1ed5915..931260f 100644 --- a/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts +++ b/src/modules/objects/domain/repositories/fakes/ObjectsFakeRepository.ts @@ -54,6 +54,12 @@ class ObjectsFakeRepository implements IObjectsRepository { return objects; } + + async updateAvailable(id: string, available: boolean): Promise { + const findIndex = this.objects.findIndex(object => object.id === id); + + this.objects[findIndex].available = available; + } } export { ObjectsFakeRepository }; diff --git a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts index 8cef30a..3d2ac68 100644 --- a/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts +++ b/src/modules/objects/infra/typeorm/repositories/ObjectsRepository.ts @@ -60,6 +60,16 @@ class ObjectsRepository implements IObjectsRepository { return object; } + + async updateAvailable(id: string, available: boolean): Promise { + await this.repository + .createQueryBuilder() + .update() + .set({ available }) + .where('id = :id') + .setParameters({ id }) + .execute(); + } } export { ObjectsRepository }; diff --git a/src/modules/objects/services/CreateObjectMessageService.ts b/src/modules/objects/services/CreateObjectMessageService.ts index c338d8d..2177b81 100644 --- a/src/modules/objects/services/CreateObjectMessageService.ts +++ b/src/modules/objects/services/CreateObjectMessageService.ts @@ -33,6 +33,8 @@ class CreateObjectMessageService { message, }); + await this.objectsRepository.updateAvailable(object_id, false); + return objectMessage; } } From 54c3bbebb73390f08eb399e5cdce53bab527f293 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 25 Jan 2022 14:36:13 -0300 Subject: [PATCH 87/92] fix: fixing bugs in tests --- src/modules/users/domain/dtos/ICreateUserDTO.ts | 2 +- .../domain/repositories/fakes/UsersFakeRepository.ts | 8 +++++++- .../users/services/tests/CreateSessionService.spec.ts | 2 ++ .../users/services/tests/CreateUserService.spec.ts | 4 ++++ .../users/services/tests/DeleteUserService.spec.ts | 1 + src/modules/users/services/tests/ListUserService.spec.ts | 1 + 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/modules/users/domain/dtos/ICreateUserDTO.ts b/src/modules/users/domain/dtos/ICreateUserDTO.ts index cbab1cf..fd8e550 100644 --- a/src/modules/users/domain/dtos/ICreateUserDTO.ts +++ b/src/modules/users/domain/dtos/ICreateUserDTO.ts @@ -1,8 +1,8 @@ interface ICreateUserDTO { name: string; email: string; - password: string; telephone: string; + password: string; } export { ICreateUserDTO }; diff --git a/src/modules/users/domain/repositories/fakes/UsersFakeRepository.ts b/src/modules/users/domain/repositories/fakes/UsersFakeRepository.ts index bb2e98d..7b619d3 100644 --- a/src/modules/users/domain/repositories/fakes/UsersFakeRepository.ts +++ b/src/modules/users/domain/repositories/fakes/UsersFakeRepository.ts @@ -26,12 +26,18 @@ class UsersFakeRepository implements IUsersRepository { return users; } - async create({ name, email, password }: ICreateUserDTO): Promise { + async create({ + name, + email, + telephone, + password, + }: ICreateUserDTO): Promise { const create = new User(); Object.assign(create, { name, email, + telephone, password, }); diff --git a/src/modules/users/services/tests/CreateSessionService.spec.ts b/src/modules/users/services/tests/CreateSessionService.spec.ts index 06e1f8b..f9b52dc 100644 --- a/src/modules/users/services/tests/CreateSessionService.spec.ts +++ b/src/modules/users/services/tests/CreateSessionService.spec.ts @@ -28,6 +28,7 @@ describe('Create Session', () => { const user = { name: 'Nome Test', email: 'test@test.com', + telephone: '99999999', password: '123456', }; @@ -54,6 +55,7 @@ describe('Create Session', () => { await usersFakeRepository.create({ name: 'Nome Test', email: 'test@test.com', + telephone: '99999999', password: '123456', }); diff --git a/src/modules/users/services/tests/CreateUserService.spec.ts b/src/modules/users/services/tests/CreateUserService.spec.ts index f0fc0c1..3d0bdb4 100644 --- a/src/modules/users/services/tests/CreateUserService.spec.ts +++ b/src/modules/users/services/tests/CreateUserService.spec.ts @@ -21,6 +21,7 @@ describe('Create User', () => { const createUser = await createUserService.execute({ name: 'Nome Test', email: 'test@test.com', + telephone: '99999999', password: '123456', }); @@ -31,12 +32,14 @@ describe('Create User', () => { const user = { name: 'Nome Test', email: 'test@test.com', + telephone: '99999999', password: '123456', }; await createUserService.execute({ name: user.name, email: user.email, + telephone: user.telephone, password: user.password, }); @@ -44,6 +47,7 @@ describe('Create User', () => { createUserService.execute({ name: user.name, email: user.email, + telephone: user.telephone, password: user.password, }), ).rejects.toBeInstanceOf(AppError); diff --git a/src/modules/users/services/tests/DeleteUserService.spec.ts b/src/modules/users/services/tests/DeleteUserService.spec.ts index a1d702c..99b4b8f 100644 --- a/src/modules/users/services/tests/DeleteUserService.spec.ts +++ b/src/modules/users/services/tests/DeleteUserService.spec.ts @@ -20,6 +20,7 @@ describe('Delete User', () => { const user = await createUserService.execute({ name: 'Nome Test', email: 'test@test.com', + telephone: '99999999', password: '123456', }); diff --git a/src/modules/users/services/tests/ListUserService.spec.ts b/src/modules/users/services/tests/ListUserService.spec.ts index 0b2c0d6..362c542 100644 --- a/src/modules/users/services/tests/ListUserService.spec.ts +++ b/src/modules/users/services/tests/ListUserService.spec.ts @@ -23,6 +23,7 @@ describe('List Users', () => { const user = await createUserService.execute({ name: 'Nome Test', email: 'test@test.com', + telephone: '99999999', password: '123456', }); From 7b37eac7a83c9677b89ae78e73f41b55476448b4 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 25 Jan 2022 18:02:00 -0300 Subject: [PATCH 88/92] feat: implementation redis --- .env.example | 3 + README.md | 4 +- package.json | 4 + src/config/cache.ts | 19 +++ .../objects/services/CreateObjectService.ts | 5 + .../objects/services/ListAllObjectsService.ts | 13 +- src/shared/cache/RedisCache.ts | 37 +++++ yarn.lock | 131 +++++++++++++++++- 8 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 src/config/cache.ts create mode 100644 src/shared/cache/RedisCache.ts diff --git a/.env.example b/.env.example index 49a0161..7918d5a 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,6 @@ PORT = 3333 APP_SECRET = 91cf4aa79dbb713fbf551ce3efa9c12d APP_WEB_URL = http://localhost:3000 +REDIS_HOST = localhost +REDIS_PORT = 6379 +REDIS_PASS = diff --git a/README.md b/README.md index 7c60784..f255c0e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Funcionalidades do Sistema -- Deve ser possível usuário se cadastrar, ler, atualizar e deletar seus dados pessoais. Visando também o controle sobre sua conta. Os usuários são dividios em usuários comuns com funcionalidades restritas para seu cadastro e usuário admnistrador com acesso a todas as funcionalidades do sistema. Os usuários comuns não poderam excluir suas contas. +- Deve ser possível usuário se cadastrar, ler, atualizar e deletar seus dados pessoais. Visando também o controle sobre sua conta. Os usuários são dividios em usuários comuns com funcionalidades restritas para seu cadastro e usuário administrador com acesso a todas as funcionalidades do sistema. Os usuários comuns não poderam excluir suas contas. - Deve ser possível que usuário faça upload do seu avatar de usuário. @@ -22,7 +22,7 @@ - Deve ser possível que o usuário filtre todos os objetos disponíveis por categorias e nome. -- Deve ser possível que o usuário administrador envie uma mensagem ao usuário que criou o objeto perdido, avisando-o que o objeto foi encontrado, com isso o objeto fica indisponível automaticamente. O dono pode se dirigir ao setor responsável para retirá-lo. +- Deve ser possível que o usuário administrador envie uma mensagem ao usuário que criou o objeto perdido, avisando-o que o objeto foi encontrado, com isso o objeto ficará indisponível automaticamente. O dono pode se dirigir ao setor responsável para retirá-lo. - Deve ser possível a listagem de todos os objetos, antes de fazer o cadastro de usuário. diff --git a/package.json b/package.json index d1def42..4684497 100644 --- a/package.json +++ b/package.json @@ -15,12 +15,14 @@ "@types/bcrypt": "^5.0.0", "@types/cors": "^2.8.12", "@types/express": "^4.17.13", + "@types/ioredis": "^4.28.7", "@types/jest": "^27.4.0", "@types/joi": "^17.2.3", "@types/jsonwebtoken": "^8.5.8", "@types/multer": "^1.4.7", "@types/node": "^17.0.8", "@types/nodemailer": "^6.4.4", + "@types/redis": "^4.0.11", "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.10.0", "@typescript-eslint/parser": "^5.10.0", @@ -44,10 +46,12 @@ "express": "^4.17.2", "express-async-errors": "^3.1.1", "handlebars": "^4.7.7", + "ioredis": "^4.28.3", "jsonwebtoken": "^8.5.1", "multer": "^1.4.4", "nodemailer": "^6.7.2", "pg": "^8.7.1", + "redis": "^4.0.2", "reflect-metadata": "^0.1.13", "tsyringe": "^4.6.0", "typeorm": "^0.2.41", diff --git a/src/config/cache.ts b/src/config/cache.ts new file mode 100644 index 0000000..ef7931d --- /dev/null +++ b/src/config/cache.ts @@ -0,0 +1,19 @@ +import { RedisOptions } from 'ioredis'; + +interface ICacheConfig { + config: { + redis: RedisOptions; + }; + driver: string; +} + +export default { + config: { + redis: { + host: process.env.REDIS_HOST, + port: process.env.REDIS_PORT, + password: process.env.REDIS_PASSWORD || undefined, + }, + }, + driver: 'redis', +} as ICacheConfig; diff --git a/src/modules/objects/services/CreateObjectService.ts b/src/modules/objects/services/CreateObjectService.ts index bc469ca..3e4603d 100644 --- a/src/modules/objects/services/CreateObjectService.ts +++ b/src/modules/objects/services/CreateObjectService.ts @@ -1,3 +1,4 @@ +import { RedisCache } from '@shared/cache/RedisCache'; import { inject, injectable } from 'tsyringe'; import { ICreateObjectDTO } from '../domain/dtos/ICreateObjectDTO'; import { IObject } from '../domain/models/IObject'; @@ -17,6 +18,8 @@ class CreateObjectService { user_id, category_id, }: ICreateObjectDTO): Promise { + const redisCache = new RedisCache(); + const object = this.objectsRepository.create({ name, comments, @@ -25,6 +28,8 @@ class CreateObjectService { category_id, }); + await redisCache.invalidate('api-lost-and-found_OBJECTS_LIST'); + return object; } } diff --git a/src/modules/objects/services/ListAllObjectsService.ts b/src/modules/objects/services/ListAllObjectsService.ts index 4518363..65379b8 100644 --- a/src/modules/objects/services/ListAllObjectsService.ts +++ b/src/modules/objects/services/ListAllObjectsService.ts @@ -1,3 +1,4 @@ +import { RedisCache } from '@shared/cache/RedisCache'; import { inject, injectable } from 'tsyringe'; import { IObject } from '../domain/models/IObject'; import { IObjectsRepository } from '../domain/repositories/IObjectsRepository'; @@ -10,7 +11,17 @@ class ListAllObjectsService { ) {} async execute(): Promise { - const objects = await this.objectsRepository.findAll(); + const redisCache = new RedisCache(); + + let objects = await redisCache.recover( + 'api-lost-and-found_OBJECTS_LIST', + ); + + if (!objects) { + objects = await this.objectsRepository.findAll(); + + await redisCache.save('api-lost-and-found_OBJECTS_LIST', objects); + } return objects; } diff --git a/src/shared/cache/RedisCache.ts b/src/shared/cache/RedisCache.ts new file mode 100644 index 0000000..33e0d8e --- /dev/null +++ b/src/shared/cache/RedisCache.ts @@ -0,0 +1,37 @@ +import Redis, { Redis as RedisClient } from 'ioredis'; +import cacheConfig from '../../config/cache'; + +class RedisCache { + private client: RedisClient; + private connected = false; + + constructor() { + if (!this.connected) { + this.client = new Redis(cacheConfig.config.redis); + this.connected = true; + } + } + + async save(key: string, value: any): Promise { + await this.client.set(key, JSON.stringify(value)); + } + + async recover(key: string): Promise { + const data = await this.client.get(key); + + if (!data) { + return null; + } + + const parsedData = JSON.parse(data) as T; + + return parsedData; + } + + async invalidate(key: string): Promise { + await this.client.del(key); + } +} + +export { RedisCache }; +//export default new RedisCache(); diff --git a/yarn.lock b/yarn.lock index 1be59a5..25d0322 100644 --- a/yarn.lock +++ b/yarn.lock @@ -527,6 +527,36 @@ semver "^7.3.5" tar "^6.1.11" +"@node-redis/bloom@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@node-redis/bloom/-/bloom-1.0.1.tgz#144474a0b7dc4a4b91badea2cfa9538ce0a1854e" + integrity sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw== + +"@node-redis/client@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@node-redis/client/-/client-1.0.2.tgz#7f09fb739675728fbc6e73536f7cd1be99bf7b8f" + integrity sha512-C+gkx68pmTnxfV+y4pzasvCH3s4UGHNOAUNhdJxGI27aMdnXNDZct7ffDHBL7bAZSGv9FSwCP5PeYvEIEKGbiA== + dependencies: + cluster-key-slot "1.1.0" + generic-pool "3.8.2" + redis-parser "3.0.0" + yallist "4.0.0" + +"@node-redis/json@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@node-redis/json/-/json-1.0.2.tgz#8ad2d0f026698dc1a4238cc3d1eb099a3bee5ab8" + integrity sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g== + +"@node-redis/search@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@node-redis/search/-/search-1.0.2.tgz#8cfc91006ea787df801d41410283e1f59027f818" + integrity sha512-gWhEeji+kTAvzZeguUNJdMSZNH2c5dv3Bci8Nn2f7VGuf6IvvwuZDSBOuOlirLVgayVuWzAG7EhwaZWK1VDnWQ== + +"@node-redis/time-series@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@node-redis/time-series/-/time-series-1.0.1.tgz#703149f8fa4f6fff377c61a0873911e7c1ba5cc3" + integrity sha512-+nTn6EewVj3GlUXPuD3dgheWqo219jTxlo6R+pg24OeVvFHx9aFGGiyOgj3vBPhWUdRZ0xMcujXV5ki4fbLyMw== + "@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" @@ -675,6 +705,13 @@ dependencies: "@types/node" "*" +"@types/ioredis@^4.28.7": + version "4.28.7" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.7.tgz#ee79987ef80597ba8c17cfbf9345859ff9233c2d" + integrity sha512-jnSGCD2/TPk02j6v6CGqaCEl0LbmLgK6jUuk/AFaSNUBV+SCHiG7E7fnwJreN6hw9GqtLAFkJs4zFbkJrz11mQ== + dependencies: + "@types/node" "*" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" @@ -765,6 +802,13 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== +"@types/redis@^4.0.11": + version "4.0.11" + resolved "https://registry.yarnpkg.com/@types/redis/-/redis-4.0.11.tgz#0bb4c11ac9900a21ad40d2a6768ec6aaf651c0e1" + integrity sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg== + dependencies: + redis "*" + "@types/serve-static@*": version "1.13.10" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" @@ -1340,6 +1384,11 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cluster-key-slot@1.1.0, cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -1537,6 +1586,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +denque@^1.1.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -2048,6 +2102,11 @@ gauge@^3.0.0: strip-ansi "^6.0.1" wide-align "^1.1.2" +generic-pool@3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9" + integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg== + 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" @@ -2268,6 +2327,23 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, i resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ioredis@^4.28.3: + version "4.28.3" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.3.tgz#b13fce8a6a7c525ba22e666d72980a3c0ba799aa" + integrity sha512-9JOWVgBnuSxpIgfpjc1OeY1OLmA4t2KOWWURTDRXky+eWO0LZhI33pQNT9gYxANUXfh5p/zYephYni6GPRsksQ== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -2949,11 +3025,26 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + lodash.isboolean@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" @@ -3297,6 +3388,11 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-map@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -3592,6 +3688,34 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@3.0.0, redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + +redis@*, redis@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.0.2.tgz#096cf716842731a24f34c7c3a996c143e2b133bb" + integrity sha512-Ip1DJ/lwuvtJz9AZ6pl1Bv33fWzk5d3iQpGzsXpi04ErkT4fq0pfGOm4k/p9DHmPGieEIOWvJ9xmIeQMooLybg== + dependencies: + "@node-redis/bloom" "^1.0.0" + "@node-redis/client" "^1.0.2" + "@node-redis/json" "^1.0.2" + "@node-redis/search" "^1.0.2" + "@node-redis/time-series" "^1.0.1" + reflect-metadata@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" @@ -3831,6 +3955,11 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -4418,7 +4547,7 @@ y18n@^5.0.5: 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, 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== From 1a9bc882b607b54915c71f30c6421ab988e4989d Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 25 Jan 2022 18:22:31 -0300 Subject: [PATCH 89/92] feat: implementation middleware rate limiter --- .env.example | 1 + package.json | 1 + .../infra/http/middlewares/rateLimiter.ts | 32 +++++++++++++++++++ src/shared/infra/http/server.ts | 4 +++ yarn.lock | 5 +++ 5 files changed, 43 insertions(+) create mode 100644 src/shared/infra/http/middlewares/rateLimiter.ts diff --git a/.env.example b/.env.example index 7918d5a..23dbbd2 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ PORT = 3333 APP_SECRET = 91cf4aa79dbb713fbf551ce3efa9c12d +APP_API_URL = http://localhost:3333 APP_WEB_URL = http://localhost:3000 REDIS_HOST = localhost REDIS_PORT = 6379 diff --git a/package.json b/package.json index 4684497..df12bb4 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "multer": "^1.4.4", "nodemailer": "^6.7.2", "pg": "^8.7.1", + "rate-limiter-flexible": "^2.3.6", "redis": "^4.0.2", "reflect-metadata": "^0.1.13", "tsyringe": "^4.6.0", diff --git a/src/shared/infra/http/middlewares/rateLimiter.ts b/src/shared/infra/http/middlewares/rateLimiter.ts new file mode 100644 index 0000000..29eaf34 --- /dev/null +++ b/src/shared/infra/http/middlewares/rateLimiter.ts @@ -0,0 +1,32 @@ +import { Request, Response, NextFunction } from 'express'; +import Redis from 'ioredis'; + +import { RateLimiterRedis } from 'rate-limiter-flexible'; +import { AppError } from '@shared/errors/AppError'; + +export default async function rateLimiter( + request: Request, + response: Response, + next: NextFunction, +): Promise { + try { + const redisClient = new Redis({ + host: process.env.REDIS_HOST, + port: Number(process.env.REDIS_PORT), + password: process.env.REDIS_PASSWORD || undefined, + }); + + const limiter = new RateLimiterRedis({ + storeClient: redisClient, + keyPrefix: 'ratelimit', + points: 5, + duration: 1, + }); + + await limiter.consume(request.ip); + + return next(); + } catch (err) { + throw new AppError('Too many requests.', 429); + } +} diff --git a/src/shared/infra/http/server.ts b/src/shared/infra/http/server.ts index 8521ab5..8fd11cc 100644 --- a/src/shared/infra/http/server.ts +++ b/src/shared/infra/http/server.ts @@ -10,6 +10,8 @@ import uploadConfig from '@config/upload'; import createConnection from '@shared/infra/typeorm'; +import rateLimiter from './middlewares/rateLimiter'; + import '@shared/container'; createConnection(); @@ -18,6 +20,8 @@ const app = express(); app.use(cors()); app.use(express.json()); +app.use(rateLimiter); + app.use('/file', express.static(uploadConfig.directory)); app.use(routes); diff --git a/yarn.lock b/yarn.lock index 25d0322..9e578b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3634,6 +3634,11 @@ range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== +rate-limiter-flexible@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/rate-limiter-flexible/-/rate-limiter-flexible-2.3.6.tgz#b1a2549dca91069c8a33d57c08a27262c0356c60" + integrity sha512-8DVFOe89rreyut/vzwBI7vgXJynyYoYnH5XogtAKs0F/neAbCTTglXxSJ7fZeZamcFXZDvMidCBvps4KM+1srw== + raw-body@2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" From fdedd60571a5d358748db58a81c01c6e00acc7a4 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Tue, 25 Jan 2022 18:27:30 -0300 Subject: [PATCH 90/92] refactor: radis cache --- src/modules/objects/services/CreateObjectService.ts | 4 +--- src/modules/objects/services/ListAllObjectsService.ts | 4 +--- src/shared/cache/RedisCache.ts | 3 +-- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/modules/objects/services/CreateObjectService.ts b/src/modules/objects/services/CreateObjectService.ts index 3e4603d..6fe28f6 100644 --- a/src/modules/objects/services/CreateObjectService.ts +++ b/src/modules/objects/services/CreateObjectService.ts @@ -1,4 +1,4 @@ -import { RedisCache } from '@shared/cache/RedisCache'; +import redisCache from '@shared/cache/RedisCache'; import { inject, injectable } from 'tsyringe'; import { ICreateObjectDTO } from '../domain/dtos/ICreateObjectDTO'; import { IObject } from '../domain/models/IObject'; @@ -18,8 +18,6 @@ class CreateObjectService { user_id, category_id, }: ICreateObjectDTO): Promise { - const redisCache = new RedisCache(); - const object = this.objectsRepository.create({ name, comments, diff --git a/src/modules/objects/services/ListAllObjectsService.ts b/src/modules/objects/services/ListAllObjectsService.ts index 65379b8..cd36565 100644 --- a/src/modules/objects/services/ListAllObjectsService.ts +++ b/src/modules/objects/services/ListAllObjectsService.ts @@ -1,4 +1,4 @@ -import { RedisCache } from '@shared/cache/RedisCache'; +import redisCache from '@shared/cache/RedisCache'; import { inject, injectable } from 'tsyringe'; import { IObject } from '../domain/models/IObject'; import { IObjectsRepository } from '../domain/repositories/IObjectsRepository'; @@ -11,8 +11,6 @@ class ListAllObjectsService { ) {} async execute(): Promise { - const redisCache = new RedisCache(); - let objects = await redisCache.recover( 'api-lost-and-found_OBJECTS_LIST', ); diff --git a/src/shared/cache/RedisCache.ts b/src/shared/cache/RedisCache.ts index 33e0d8e..cf333ef 100644 --- a/src/shared/cache/RedisCache.ts +++ b/src/shared/cache/RedisCache.ts @@ -33,5 +33,4 @@ class RedisCache { } } -export { RedisCache }; -//export default new RedisCache(); +export default new RedisCache(); From 0274efdf8f5b8d7f3e99d6ef24e125b47d8fd2e4 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 26 Jan 2022 01:18:20 -0300 Subject: [PATCH 91/92] chore: update readme --- README.md | 16 +++++++++++++++- .../objects/services/CreateObjectService.ts | 2 +- .../objects/services/ListAllObjectsService.ts | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f255c0e..8a14105 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Objetivo Geral -- Desenvolver um software para realizar o gerenciamento de objetos achados e perdidos. +- Desenvolvimento de uma API Restful para realizar o gerenciamento de objetos achados e perdidos. ## Funcionalidades do Sistema @@ -27,3 +27,17 @@ - Deve ser possível a listagem de todos os objetos, antes de fazer o cadastro de usuário. ## Ferramentas e Tecnologias Utilizadas + +- Conceitos de boas práticas e qualidade no código, usando Design Patterns, Domain Driven Design (DDD) e Princípios SOLID, além de introduzir Testes Automatizados com o framework Jest. + +- Node.js com Typescript; + +- Express; + +- TypeORM; + +- PostgreSQL; + +- Redis; + +- Docker; diff --git a/src/modules/objects/services/CreateObjectService.ts b/src/modules/objects/services/CreateObjectService.ts index 6fe28f6..90b5db6 100644 --- a/src/modules/objects/services/CreateObjectService.ts +++ b/src/modules/objects/services/CreateObjectService.ts @@ -1,4 +1,4 @@ -import redisCache from '@shared/cache/RedisCache'; +import redisCache from '../../../shared/cache/RedisCache'; import { inject, injectable } from 'tsyringe'; import { ICreateObjectDTO } from '../domain/dtos/ICreateObjectDTO'; import { IObject } from '../domain/models/IObject'; diff --git a/src/modules/objects/services/ListAllObjectsService.ts b/src/modules/objects/services/ListAllObjectsService.ts index cd36565..2da3acf 100644 --- a/src/modules/objects/services/ListAllObjectsService.ts +++ b/src/modules/objects/services/ListAllObjectsService.ts @@ -1,4 +1,4 @@ -import redisCache from '@shared/cache/RedisCache'; +import redisCache from '../../../shared/cache/RedisCache'; import { inject, injectable } from 'tsyringe'; import { IObject } from '../domain/models/IObject'; import { IObjectsRepository } from '../domain/repositories/IObjectsRepository'; From e68c6340dd0ea7dfb8db6bab7705a89dca0dfdf2 Mon Sep 17 00:00:00 2001 From: juniorsilvaeng Date: Wed, 26 Jan 2022 01:41:31 -0300 Subject: [PATCH 92/92] chore: validation message and readme --- README.md | 8 ++++++-- src/modules/objects/infra/http/routes/objects.routes.ts | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8a14105..ffae3f4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Objetivo Geral -- Desenvolvimento de uma API Restful para realizar o gerenciamento de objetos achados e perdidos. +- API Restful para realizar o gerenciamento de objetos achados e perdidos. ## Funcionalidades do Sistema @@ -28,7 +28,7 @@ ## Ferramentas e Tecnologias Utilizadas -- Conceitos de boas práticas e qualidade no código, usando Design Patterns, Domain Driven Design (DDD) e Princípios SOLID, além de introduzir Testes Automatizados com o framework Jest. +- Conceitos de boas práticas e qualidade no código, usando Design Patterns, Clean Architecture, Domain Driven Design (DDD) e Princípios SOLID, além de introduzir Testes Automatizados com o framework Jest e autenticação via JWT Token. - Node.js com Typescript; @@ -41,3 +41,7 @@ - Redis; - Docker; + +- Celebrate Validation; + +- Rate Limiter; diff --git a/src/modules/objects/infra/http/routes/objects.routes.ts b/src/modules/objects/infra/http/routes/objects.routes.ts index 43d1ac8..f713ad1 100644 --- a/src/modules/objects/infra/http/routes/objects.routes.ts +++ b/src/modules/objects/infra/http/routes/objects.routes.ts @@ -49,6 +49,13 @@ objectsRoutes.post( '/message', ensureAuthenticated, ensureAdmin, + celebrate({ + [Segments.BODY]: { + user_id: Joi.string().required().uuid(), + object_id: Joi.string().required().uuid(), + message: Joi.string().required(), + }, + }), createObjectMessageController.handle, );