diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..9a221c3 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,110 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "parserOptions": { + "project": [ + "./tsconfig.json", + "./tsconfig.test.json" + ] + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "indent": [ + "error", + 4, + { + "SwitchCase": 1 + } + ], + "no-trailing-spaces": "error", + "max-len": [ + "error", + { + "code": 120, + "ignoreTemplateLiterals": true, + "ignoreRegExpLiterals": true + } + ], + "semi": "off", + "@typescript-eslint/semi": [ + "error" + ], + "no-extra-semi": "error", + "eol-last": "error", + "comma-dangle": "off", + "@typescript-eslint/comma-dangle": [ + "error", + { + "arrays": "always-multiline", + "objects": "always-multiline", + "imports": "always-multiline", + "exports": "always-multiline", + "functions": "always-multiline", + "enums": "always-multiline", + "generics": "always-multiline", + "tuples": "always-multiline" + } + ], + "no-extra-parens": "off", + "@typescript-eslint/no-extra-parens": [ + "error" + ], + "no-nested-ternary": "error", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/explicit-module-boundary-types": "error", + "@typescript-eslint/no-unnecessary-condition": "error", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_" + } + ], + "@typescript-eslint/no-non-null-assertion": "error", + "no-useless-return": "error", + "no-useless-constructor": "off", + "@typescript-eslint/no-useless-constructor": [ + "error" + ], + "no-return-await": "off", + "@typescript-eslint/return-await": [ + "error", + "always" + ], + "@typescript-eslint/explicit-member-accessibility": [ + "error", + { + "accessibility": "explicit" + } + ], + "@typescript-eslint/no-floating-promises": "error" + }, + "ignorePatterns": [ + "jest.config.js", + "dist/**/*", + "config/**/*" + ], + "overrides": [ + { + "files": [ + "test/**/*" + ], + "rules": { + "max-len": [ + "error", + { + "code": 120, + "ignoreTemplateLiterals": true, + "ignoreRegExpLiterals": true, + "ignoreStrings": true + } + ] + } + } + ] +} diff --git a/.gitignore b/.gitignore index 76fb2e5..5b5cd12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea node_modules -dist \ No newline at end of file +dist +yarn-error.log diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f27a8df --- /dev/null +++ b/LICENSE @@ -0,0 +1,8 @@ + +Copyright 2020 Alice Gaudon + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 08fe6f8..0b08eb4 100644 --- a/README.md +++ b/README.md @@ -1 +1,33 @@ -# WMS-Core \ No newline at end of file +# Structure Web Application Framework + +A NodeJS TypeScript web application framework (duh). + +## /!\ Still in development! There are not near enough tests /!\ + +Use at your own risk. Also please feel free to contribute with issues, bug reports and pull requests. + +## Features + +### Application building + +- Model, View, Controller +- Uses express +- Custom Middleware classes that enable advanced modularity +- Modular models (you can add components with some definition automation) +- Simple database migrations (raw sql queries for now) +- Nunjucks for the view template engine +- Mail template system using Nunjucks + MJML +- Beautiful logging thanks to `tslog` + +### Databases + +- MySQL (persistent data) +- Redis (cache, session) +- (more to come) + +### Common systems + +- Advanced modular multi-factor authentication system +- CSRF protection +- WebSocket server with Controller-style endpoint listeners +- WIP: automatic updates diff --git a/config/default.json5 b/config/default.json5 new file mode 100644 index 0000000..a1c8c4d --- /dev/null +++ b/config/default.json5 @@ -0,0 +1,54 @@ +{ + app: { + name: 'Example App', + contact_email: 'contact@example.net', + display_email_warning: true, + }, + log: { + level: "DEBUG", + verbose: true, + db_level: "ERROR", + }, + public_url: "http://localhost:4899", + public_websocket_url: "ws://localhost:4899", + listen_addr: '127.0.0.1', + port: 4899, + gitlab_webhook_token: 'default', + mysql: { + connectionLimit: 10, + host: "localhost", + user: "root", + password: "", + database: "swaf", + create_database_automatically: false, + }, + redis: { + host: "127.0.0.1", + port: 6379, + prefix: 'swaf', + }, + session: { + secret: 'default', + cookie: { + secure: false, + maxAge: 31557600000, // 1 year + }, + }, + mail: { + host: "127.0.0.1", + port: "1025", + secure: false, + username: "", + password: "", + allow_invalid_tls: true, + from: 'contact@example.net', + from_name: 'Example App', + }, + view: { + cache: false, + }, + magic_link: { + validity_period: 20, + }, + approval_mode: false, +} diff --git a/config/default.ts b/config/default.ts deleted file mode 100644 index d9172d6..0000000 --- a/config/default.ts +++ /dev/null @@ -1,36 +0,0 @@ -export default { - log_level: "DEV", - db_log_level: "ERROR", - public_url: "http://localhost:4899", - public_websocket_url: "ws://localhost:4899", - port: 4899, - mysql: { - connectionLimit: 10, - host: "localhost", - user: "root", - password: "", - database: "wms2", - create_database_automatically: false - }, - redis: { - host: "127.0.0.1", - port: 6379 - }, - session: { - secret: "very_secret_not_known", - cookie: { - secure: false - } - }, - mail: { - host: "127.0.0.1", - port: "1025", - secure: false, - username: "", - password: "", - allow_invalid_tls: true - }, - view: { - cache: false - } -}; \ No newline at end of file diff --git a/config/production.json5 b/config/production.json5 new file mode 100644 index 0000000..f54e137 --- /dev/null +++ b/config/production.json5 @@ -0,0 +1,21 @@ +{ + log: { + level: "DEV", + verbose: false, + db_level: "ERROR", + }, + public_url: "https://swaf.example", + public_websocket_url: "wss://swaf.example", + session: { + cookie: { + secure: true, + }, + }, + mail: { + secure: true, + allow_invalid_tls: false, + }, + magic_link: { + validity_period: 900, + }, +} diff --git a/config/production.ts b/config/production.ts deleted file mode 100644 index fd0c69b..0000000 --- a/config/production.ts +++ /dev/null @@ -1,15 +0,0 @@ -export default { - log_level: "DEBUG", - db_log_level: "ERROR", - public_url: "https://watch-my.stream", - public_websocket_url: "wss://watch-my.stream", - session: { - cookie: { - secure: true - } - }, - mail: { - secure: true, - allow_invalid_tls: false - } -}; \ No newline at end of file diff --git a/config/test.json5 b/config/test.json5 new file mode 100644 index 0000000..d83228f --- /dev/null +++ b/config/test.json5 @@ -0,0 +1,14 @@ +{ + mysql: { + host: "localhost", + user: "root", + password: "", + database: "swaf_test", + create_database_automatically: true, + }, + session: { + cookie: { + maxAge: 1000, // 1s + }, + }, +} diff --git a/config/test.ts b/config/test.ts deleted file mode 100644 index 649dec2..0000000 --- a/config/test.ts +++ /dev/null @@ -1,9 +0,0 @@ -export default { - mysql: { - host: "localhost", - user: "root", - password: "", - database: "wms2_test", - create_database_automatically: true - } -}; \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index b61dffa..ccf1d63 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,4 +1,9 @@ module.exports = { + globals: { + 'ts-jest': { + tsconfig: 'tsconfig.test.json', + } + }, transform: { "^.+\\.ts$": "ts-jest" }, @@ -10,5 +15,5 @@ module.exports = { testMatch: [ '**/test/**/*.test.ts' ], - testEnvironment: 'node' + testEnvironment: 'node', }; \ No newline at end of file diff --git a/package.json b/package.json index a3bb867..75ef1c9 100644 --- a/package.json +++ b/package.json @@ -1,58 +1,81 @@ { - "name": "wms-core", - "version": "0.2.7", - "description": "Node web framework", - "repository": "git@gitlab.com:ArisuOngaku/wms-core.git", + "name": "swaf", + "version": "0.23.0", + "description": "Structure Web Application Framework.", + "repository": "https://eternae.ink/arisu/swaf", "author": "Alice Gaudon ", "license": "MIT", + "readme": "README.md", "publishConfig": { - "registry": "http://127.0.0.1:4873", - "access": "restricted" + "registry": "https://registry.npmjs.com", + "access": "public" }, - "main": "dist/index.js", + "main": "dist/src/main.js", "types": "dist/index.d.ts", "scripts": { "test": "jest --verbose --runInBand", - "build": "(test ! -d dist || rm -r dist) && tsc && cp package.json dist/ && mkdir dist/types && cp src/types/* dist/types/ && mv dist/src/* dist/ && rm -r dist/src", - "publish_to_local": "yarn test && yarn build && cd dist && yarn publish" + "clean": "(test ! -d dist || rm -r dist)", + "compile": "yarn clean && tsc", + "dev": "concurrently -k -n \"Typescript,Node,Webpack,Maildev\" -p \"[{name}]\" -c \"blue,green,red,yellow\" \"tsc --watch\" \"nodemon\" \"maildev\"", + "build": "yarn compile && cp -r package.json yarn.lock README.md config/ views/ dist/ && mkdir dist/types && cp src/types/* dist/types/", + "lint": "eslint . --ext .js,.jsx,.ts,.tsx", + "release": "yarn lint && yarn test && yarn build && cd dist && yarn publish" }, "devDependencies": { - "@types/config": "^0.0.36", - "@types/connect-flash": "^0.0.35", - "@types/connect-redis": "^0.0.13", - "@types/cookie": "^0.3.3", + "@types/compression": "^1.7.0", + "@types/config": "^0.0.38", + "@types/connect-flash": "^0.0.36", + "@types/cookie": "^0.4.0", "@types/cookie-parser": "^1.4.2", - "@types/jest": "^25.2.1", - "@types/mjml": "^4.0.4", - "@types/on-finished": "^2.3.1", - "@types/uuid": "^7.0.2", - "jest": "^25.4.0", - "ts-jest": "^25.4.0", - "typescript": "^3.8.3" - }, - "dependencies": { "@types/express": "^4.17.6", "@types/express-session": "^1.17.0", + "@types/formidable": "^1.0.31", + "@types/geoip-lite": "^1.1.31", + "@types/jest": "^26.0.4", + "@types/mjml": "^4.0.4", "@types/mysql": "^2.15.10", + "@types/nanoid": "^2.1.0", + "@types/node-fetch": "^2.5.7", "@types/nodemailer": "^6.4.0", "@types/nunjucks": "^3.1.3", + "@types/on-finished": "^2.3.1", "@types/redis": "^2.8.18", + "@types/supertest": "^2.0.10", + "@types/uuid": "^8.0.0", "@types/ws": "^7.2.4", + "@typescript-eslint/eslint-plugin": "^4.2.0", + "@typescript-eslint/parser": "^4.2.0", + "concurrently": "^5.3.0", + "eslint": "^7.9.0", + "jest": "^26.1.0", + "maildev": "^1.1.0", + "node-fetch": "^2.6.0", + "nodemon": "^2.0.6", + "supertest": "^6.0.0", + "ts-jest": "^26.1.1", + "typescript": "^4.0.2" + }, + "dependencies": { + "argon2": "^0.27.0", + "compression": "^1.7.4", "config": "^3.3.1", "connect-flash": "^0.1.1", - "connect-redis": "^4.0.4", "cookie": "^0.4.1", "cookie-parser": "^1.4.5", "express": "^4.17.1", "express-session": "^1.17.1", + "formidable": "^1.2.2", + "geoip-lite": "^1.4.2", "mjml": "^4.6.2", "mysql": "^2.18.1", + "nanoid": "^3.1.20", "nodemailer": "^6.4.6", "nunjucks": "^3.2.1", "on-finished": "^2.3.0", "redis": "^3.0.2", - "ts-node": "^8.9.0", - "uuid": "^7.0.3", + "ts-node": "^9.0.0", + "tslog": "^3.0.1", + "uuid": "^8.0.0", "ws": "^7.2.3" } } diff --git a/src/Application.ts b/src/Application.ts index ec0f38b..02db79c 100644 --- a/src/Application.ts +++ b/src/Application.ts @@ -1,45 +1,64 @@ import express, {NextFunction, Request, Response, Router} from 'express'; import {BadRequestError, HttpError, NotFoundHttpError, ServerError, ServiceUnavailableHttpError} from "./HttpError"; import {lib} from "nunjucks"; -import Logger from "./Logger"; import WebSocketListener from "./WebSocketListener"; import ApplicationComponent from "./ApplicationComponent"; import Controller from "./Controller"; import MysqlConnectionManager from "./db/MysqlConnectionManager"; -import Migration from "./db/Migration"; -import TemplateError = lib.TemplateError; +import Migration, {MigrationType} from "./db/Migration"; import {Type} from "./Utils"; +import LogRequestsComponent from "./components/LogRequestsComponent"; +import {ValidationBag, ValidationError} from "./db/Validator"; +import config from "config"; +import * as fs from "fs"; +import SecurityError from "./SecurityError"; +import * as path from "path"; +import CacheProvider from "./CacheProvider"; +import RedisComponent from "./components/RedisComponent"; +import Extendable from "./Extendable"; +import {logger, loggingContextMiddleware} from "./Logger"; +import TemplateError = lib.TemplateError; -export default abstract class Application { +export default abstract class Application implements Extendable> { private readonly version: string; + private readonly ignoreCommandLine: boolean; private readonly controllers: Controller[] = []; - private readonly webSocketListeners: { [p: string]: WebSocketListener } = {}; - private readonly components: ApplicationComponent[] = []; + private readonly webSocketListeners: { [p: string]: WebSocketListener } = {}; + private readonly components: ApplicationComponent[] = []; + private cacheProvider?: CacheProvider; private ready: boolean = false; - protected constructor(version: string) { + protected constructor(version: string, ignoreCommandLine: boolean = false) { this.version = version; + this.ignoreCommandLine = ignoreCommandLine; } - protected abstract getMigrations(): Type[]; + protected abstract getMigrations(): MigrationType[]; - protected abstract async init(): Promise; + protected abstract init(): Promise; - protected use(thing: Controller | WebSocketListener | ApplicationComponent) { + protected use(thing: Controller | WebSocketListener | ApplicationComponent): void { if (thing instanceof Controller) { + thing.setApp(this); this.controllers.push(thing); } else if (thing instanceof WebSocketListener) { const path = thing.path(); this.webSocketListeners[path] = thing; - Logger.info(`Added websocket listener on ${path}`); + thing.init(this); + logger.info(`Added websocket listener on ${path}`); } else { + thing.setApp(this); this.components.push(thing); + + if (thing instanceof RedisComponent) { + this.cacheProvider = thing; + } } } public async start(): Promise { - Logger.info(`${this.constructor.name} v${this.version} - hi`); + logger.info(`${config.get('app.name')} v${this.version} - hi`); process.once('SIGINT', () => { this.stop().catch(console.error); }); @@ -47,30 +66,70 @@ export default abstract class Application { // Register migrations MysqlConnectionManager.registerMigrations(this.getMigrations()); + // Process command line + if (!this.ignoreCommandLine && await this.processCommandLine()) { + await this.stop(); + return; + } + // Register all components and alike await this.init(); + // Security + if (process.env.NODE_ENV === 'production') { + await this.checkSecuritySettings(); + } + // Init express const app = express(); - const router = express.Router({}); - app.use(router); - // Error handler - app.use((err: any, req: Request, res: Response, next: NextFunction) => { - if (res.headersSent) { - return next(err); + // Logging context + app.use(loggingContextMiddleware); + + // Routers + const initRouter = express.Router(); + const handleRouter = express.Router(); + app.use(initRouter); + app.use(handleRouter); + + // Error handlers + app.use((err: unknown, req: Request, res: Response, next: NextFunction) => { + if (res.headersSent) return next(err); + + // Transform single validation errors into a validation bag for convenience + if (err instanceof ValidationError) { + const bag = new ValidationBag(); + bag.addMessage(err); + err = bag; } - let errorID: string; - - let logStr = `${req.method} ${req.originalUrl} - `; - if (err instanceof BadRequestError || err instanceof ServiceUnavailableHttpError) { - logStr += `${err.errorCode} ${err.name}`; - errorID = Logger.silentError(err, logStr); - } else { - errorID = Logger.error(err, logStr + `500 Internal Error`, err); + if (err instanceof ValidationBag) { + const bag = err; + res.format({ + json: () => { + res.status(400); + res.json({ + status: 'error', + code: 400, + message: 'Invalid form data', + messages: bag.getMessages(), + }); + }, + text: () => { + res.status(400); + res.send('Error: ' + bag.getMessages()); + }, + html: () => { + req.flash('validation', bag.getMessages()); + res.redirect(req.getPreviousUrl() || Controller.route('home')); + }, + }); + return; } + const errorId = LogRequestsComponent.logRequest(req, res, err, '500 Internal Error', + err instanceof BadRequestError || err instanceof ServiceUnavailableHttpError); + let httpError: HttpError; if (err instanceof HttpError) { @@ -78,7 +137,7 @@ export default abstract class Application { } else if (err instanceof TemplateError && err.cause instanceof HttpError) { httpError = err.cause; } else { - httpError = new ServerError('Internal server error.', err); + httpError = new ServerError('Internal server error.', err instanceof Error ? err : undefined); } res.status(httpError.errorCode); @@ -88,7 +147,7 @@ export default abstract class Application { error_code: httpError.errorCode, error_message: httpError.message, error_instructions: httpError.instructions, - error_id: errorID, + error_id: errorId, }); }, json: () => { @@ -97,63 +156,140 @@ export default abstract class Application { code: httpError.errorCode, message: httpError.message, instructions: httpError.instructions, - error_id: errorID, + error_id: errorId, }); }, default: () => { - res.type('txt').send(`${httpError.errorCode} - ${httpError.message}\n\n${httpError.instructions}\n\nError ID: ${errorID}`); - } + res.type('txt').send(`${httpError.errorCode} - ${httpError.message}\n\n${httpError.instructions}\n\nError ID: ${errorId}`); + }, }); }); - // Start all components + // Start components for (const component of this.components) { - await component.start(app, router); + await component.start?.(app); + } + + // Components routes + for (const component of this.components) { + if (component.init) { + component.setCurrentRouter(initRouter); + await component.init(initRouter); + } + + if (component.handle) { + component.setCurrentRouter(handleRouter); + await component.handle(handleRouter); + } + + component.setCurrentRouter(null); } // Routes - this.routes(router); + this.routes(initRouter, handleRouter); this.ready = true; } - async stop(): Promise { - Logger.info('Stopping application...'); - - for (const component of this.components) { - await component.stop(); + protected async processCommandLine(): Promise { + const args = process.argv; + for (let i = 2; i < args.length; i++) { + switch (args[i]) { + case '--verbose': + logger.setSettings({minLevel: "trace"}); + break; + case '--full-http-requests': + LogRequestsComponent.logFullHttpRequests(); + break; + case 'migration': + await MysqlConnectionManager.migrationCommand(args.slice(i + 1)); + return true; + default: + logger.warn('Unrecognized argument', args[i]); + return true; + } } - - Logger.info(`${this.constructor.name} v${this.version} - bye`); + return false; } - private routes(rootRouter: Router) { - for (const controller of this.controllers) { - if (controller.hasGlobalHandlers()) { - controller.setupGlobalHandlers(rootRouter); + private async checkSecuritySettings(): Promise { + // Check config file permissions + const configDir = 'config'; + for (const file of fs.readdirSync(configDir)) { + const fullPath = path.resolve(configDir, file); + const stats = fs.lstatSync(fullPath); + if (stats.uid !== process.getuid()) + throw new SecurityError(`${fullPath} is not owned by this process (${process.getuid()}).`); - Logger.info(`Registered global middlewares for controller ${controller.constructor.name}`); + const mode = (stats.mode & parseInt('777', 8)).toString(8); + if (mode !== '400') + throw new SecurityError(`${fullPath} is ${mode}; should be 400.`); + } + + // Check security fields + for (const component of this.components) { + await component.checkSecuritySettings?.(); + } + } + + public async stop(): Promise { + logger.info('Stopping application...'); + + for (const component of this.components) { + await component.stop?.(); + } + + logger.info(`${this.constructor.name} v${this.version} - bye`); + } + + private routes(initRouter: Router, handleRouter: Router) { + for (const controller of this.controllers) { + if (controller.hasGlobalMiddlewares()) { + controller.setupGlobalHandlers(handleRouter); + + logger.info(`Registered global middlewares for controller ${controller.constructor.name}`); } } for (const controller of this.controllers) { - const router = express.Router(); - controller.setupRoutes(router); - rootRouter.use(controller.getRoutesPrefix(), router); + const {mainRouter, fileUploadFormRouter} = controller.setupRoutes(); + initRouter.use(controller.getRoutesPrefix(), fileUploadFormRouter); + handleRouter.use(controller.getRoutesPrefix(), mainRouter); - Logger.info(`> Registered routes for controller ${controller.constructor.name}`); + logger.info(`> Registered routes for controller ${controller.constructor.name} at ${controller.getRoutesPrefix()}`); } - rootRouter.use((req: Request) => { + handleRouter.use((req: Request) => { throw new NotFoundHttpError('page', req.originalUrl); }); } - public getWebSocketListeners(): { [p: string]: WebSocketListener } { - return this.webSocketListeners; - } - public isReady(): boolean { return this.ready; } -} \ No newline at end of file + + public getVersion(): string { + return this.version; + } + + public getWebSocketListeners(): { [p: string]: WebSocketListener } { + return this.webSocketListeners; + } + + public getCache(): CacheProvider | null { + return this.cacheProvider || null; + } + + public as>(type: Type): C { + const module = this.components.find(component => component.constructor === type) || + Object.values(this.webSocketListeners).find(listener => listener.constructor === type); + if (!module) throw new Error(`This app doesn't have a ${type.name} component.`); + return module as C; + } + + public asOptional>(type: Type): C | null { + const module = this.components.find(component => component.constructor === type) || + Object.values(this.webSocketListeners).find(listener => listener.constructor === type); + return module ? module as C : null; + } +} diff --git a/src/ApplicationComponent.ts b/src/ApplicationComponent.ts index 183303e..7f336f8 100644 --- a/src/ApplicationComponent.ts +++ b/src/ApplicationComponent.ts @@ -1,22 +1,24 @@ import {Express, Router} from "express"; -import Logger from "./Logger"; +import {logger} from "./Logger"; import {sleep} from "./Utils"; +import Application from "./Application"; +import config from "config"; +import SecurityError from "./SecurityError"; +import Middleware, {MiddlewareType} from "./Middleware"; -export default abstract class ApplicationComponent { - private val?: T; +export default abstract class ApplicationComponent { + private currentRouter?: Router; + private app?: Application; - public abstract async start(app: Express, router: Router): Promise; + public async checkSecuritySettings?(): Promise; - public abstract async stop(): Promise; + public async start?(expressApp: Express): Promise; - protected export(val: T) { - this.val = val; - } + public async init?(router: Router): Promise; - public import(): T { - if (!this.val) throw 'Cannot import if nothing was exported.'; - return this.val; - } + public async handle?(router: Router): Promise; + + public async stop?(): Promise; protected async prepare(name: string, prepare: () => Promise): Promise { let err; @@ -26,23 +28,55 @@ export default abstract class ApplicationComponent { err = null; } catch (e) { err = e; - Logger.error(err, `${name} failed to prepare; retrying in 5s...`) + logger.error(err, `${name} failed to prepare; retrying in 5s...`); await sleep(5000); } } while (err); - Logger.info(`${name} ready!`); + logger.info(`${name} ready!`); } - protected async close(thingName: string, thing: any, fn: Function): Promise { + protected async close(thingName: string, fn: (callback: (err?: Error | null) => void) => void): Promise { try { - await new Promise((resolve, reject) => fn.call(thing, (err: any) => { + await new Promise((resolve, reject) => fn((err?: Error | null) => { if (err) reject(err); else resolve(); })); - Logger.info(`${thingName} closed.`); + logger.info(`${thingName} closed.`); } catch (e) { - Logger.error(e, `An error occurred while closing the ${thingName}.`); + logger.error(e, `An error occurred while closing the ${thingName}.`); } } -} \ No newline at end of file + + protected checkSecurityConfigField(field: string): void { + if (!config.has(field) || config.get(field) === 'default') { + throw new SecurityError(`${field} field not configured.`); + } + } + + protected use(middleware: MiddlewareType): void { + if (!this.currentRouter) throw new Error('Cannot call this method outside init() and handle().'); + + const instance = new middleware(this.getApp()); + this.currentRouter.use(async (req, res, next) => { + try { + await instance.getRequestHandler()(req, res, next); + } catch (e) { + next(e); + } + }); + } + + public setCurrentRouter(router: Router | null): void { + this.currentRouter = router || undefined; + } + + protected getApp(): Application { + if (!this.app) throw new Error('app field not initialized.'); + return this.app; + } + + public setApp(app: Application): void { + this.app = app; + } +} diff --git a/src/CacheProvider.ts b/src/CacheProvider.ts new file mode 100644 index 0000000..c957667 --- /dev/null +++ b/src/CacheProvider.ts @@ -0,0 +1,14 @@ +export default interface CacheProvider { + get(key: string, defaultValue?: T): Promise; + + has(key: string): Promise; + + forget(key: string): Promise; + + /** + * @param key + * @param value + * @param ttl in ms + */ + remember(key: string, value: string, ttl: number): Promise; +} diff --git a/src/Controller.ts b/src/Controller.ts index 9304438..abdd228 100644 --- a/src/Controller.ts +++ b/src/Controller.ts @@ -1,50 +1,61 @@ -import {RequestHandler, Router} from "express"; +import express, {IRouter, RequestHandler, Router} from "express"; import {PathParams} from "express-serve-static-core"; import config from "config"; -import Logger from "./Logger"; +import {logger} from "./Logger"; +import FileUploadMiddleware from "./FileUploadMiddleware"; +import * as querystring from "querystring"; +import {ParsedUrlQueryInput} from "querystring"; +import Middleware, {MiddlewareType} from "./Middleware"; +import Application from "./Application"; export default abstract class Controller { - private static readonly routes: { [p: string]: string } = {}; + private static readonly routes: { [p: string]: string | undefined } = {}; - public static route(route: string, params: RouteParams = [], absolute: boolean = false): string { + public static route( + route: string, + params: RouteParams = [], + query: ParsedUrlQueryInput = {}, + absolute: boolean = false, + ): string { let path = this.routes[route]; if (path === undefined) throw new Error(`Unknown route for name ${route}.`); if (typeof params === 'string' || typeof params === 'number') { - path = path.replace(/:[a-zA-Z_-]+\??/, '' + params); + path = path.replace(/:[a-zA-Z_-]+\??/g, '' + params); } else if (Array.isArray(params)) { let i = 0; - for (const match of path.matchAll(/:[a-zA-Z_-]+\??/)) { + for (const match of path.matchAll(/:[a-zA-Z_-]+(\(.*\))?\??/g)) { if (match.length > 0) { path = path.replace(match[0], typeof params[i] !== 'undefined' ? params[i] : ''); } i++; } - path = path.replace(/\/+/, '/'); + path = path.replace(/\/+/g, '/'); } else { - for (const key in params) { - if (params.hasOwnProperty(key)) { - path = path.replace(new RegExp(`:${key}\\??`), params[key]); - } + for (const key of Object.keys(params)) { + path = path.replace(new RegExp(`:${key}\\??`), params[key]); } } - return `${absolute ? config.get('public_url') : ''}${path}`; + const queryStr = querystring.stringify(query); + return `${absolute ? config.get('public_url') : ''}${path}` + (queryStr.length > 0 ? '?' + queryStr : ''); } - private router?: Router; + private readonly router: Router = express.Router(); + private readonly fileUploadFormRouter: Router = express.Router(); + private app?: Application; - public getGlobalHandlers(): RequestHandler[] { + public getGlobalMiddlewares(): Middleware[] { return []; } - public hasGlobalHandlers(): boolean { - return this.getGlobalHandlers().length > 0; + public hasGlobalMiddlewares(): boolean { + return this.getGlobalMiddlewares().length > 0; } public setupGlobalHandlers(router: Router): void { - for (const globalHandler of this.getGlobalHandlers()) { - router.use(this.wrap(globalHandler)); + for (const middleware of this.getGlobalMiddlewares()) { + router.use(this.wrap(middleware.getRequestHandler())); } } @@ -54,36 +65,93 @@ export default abstract class Controller { public abstract routes(): void; - public setupRoutes(router: Router): void { - this.router = router; + public setupRoutes(): { mainRouter: Router, fileUploadFormRouter: Router } { this.routes(); + return { + mainRouter: this.router, + fileUploadFormRouter: this.fileUploadFormRouter, + }; } - protected use(handler: RequestHandler) { - this.router?.use(this.wrap(handler)); + protected use(handler: RequestHandler): void { + this.router.use(this.wrap(handler)); + logger.info('Installed anonymous middleware on ' + this.getRoutesPrefix()); } - protected get(path: PathParams, handler: RequestHandler, routeName?: string, ...middlewares: RequestHandler[]) { + protected useMiddleware(...middlewares: MiddlewareType[]): void { + for (const middleware of middlewares) { + const instance = new middleware(this.getApp()); + if (instance instanceof FileUploadMiddleware) { + this.fileUploadFormRouter.use(this.wrap(instance.getRequestHandler())); + } else { + this.router.use(this.wrap(instance.getRequestHandler())); + } + + logger.info('Installed ' + middleware.name + ' on ' + this.getRoutesPrefix()); + } + } + + protected get( + path: PathParams, + handler: RequestHandler, + routeName?: string, + ...middlewares: (MiddlewareType)[] + ): void { + this.handle('get', path, handler, routeName, ...middlewares); + } + + protected post( + path: PathParams, + handler: RequestHandler, + routeName?: string, + ...middlewares: (MiddlewareType)[] + ): void { + this.handle('post', path, handler, routeName, ...middlewares); + } + + protected put( + path: PathParams, + handler: RequestHandler, + routeName?: string, + ...middlewares: (MiddlewareType)[] + ): void { + this.handle('put', path, handler, routeName, ...middlewares); + } + + protected delete( + path: PathParams, + handler: RequestHandler, + routeName?: string, + ...middlewares: (MiddlewareType)[] + ): void { + this.handle('delete', path, handler, routeName, ...middlewares); + } + + private handle( + action: Exclude, + path: PathParams, + handler: RequestHandler, + routeName?: string, + ...middlewares: (MiddlewareType)[] + ): void { this.registerRoutes(path, handler, routeName); for (const middleware of middlewares) { - this.router?.get(path, this.wrap(middleware)); + const instance = new middleware(this.getApp()); + if (instance instanceof FileUploadMiddleware) { + this.fileUploadFormRouter[action](path, this.wrap(instance.getRequestHandler())); + } else { + this.router[action](path, this.wrap(instance.getRequestHandler())); + } } - this.router?.get(path, this.wrap(handler)); - } - - protected post(path: PathParams, handler: RequestHandler, routeName?: string, ...middlewares: RequestHandler[]) { - this.registerRoutes(path, handler, routeName); - for (const middleware of middlewares) { - this.router?.post(path, this.wrap(middleware)); - } - this.router?.post(path, this.wrap(handler)); + this.router[action](path, this.wrap(handler)); } private wrap(handler: RequestHandler): RequestHandler { - return (req, res, next) => { - const promise = handler.call(this, req, res, next); - if (promise instanceof Promise) { - promise.catch(err => next(err)); + return async (req, res, next) => { + try { + await handler.call(this, req, res, next); + } catch (e) { + next(e); } }; } @@ -108,13 +176,22 @@ export default abstract class Controller { if (!Controller.routes[routeName]) { if (typeof routePath === 'string') { - Logger.info(`Route ${routeName} has path ${routePath}`); + logger.info(`Route ${routeName} has path ${routePath}`); Controller.routes[routeName] = routePath; } else { - Logger.warn(`Cannot assign path to route ${routeName}.`); + logger.warn(`Cannot assign path to route ${routeName}.`); } } } + + protected getApp(): Application { + if (!this.app) throw new Error('Application not initialized.'); + return this.app; + } + + public setApp(app: Application): void { + this.app = app; + } } -export type RouteParams = { [p: string]: string } | string[] | string | number; \ No newline at end of file +export type RouteParams = { [p: string]: string } | string[] | string | number; diff --git a/src/Extendable.ts b/src/Extendable.ts new file mode 100644 index 0000000..2ebfa98 --- /dev/null +++ b/src/Extendable.ts @@ -0,0 +1,7 @@ +import {Type} from "./Utils"; + +export default interface Extendable { + as(type: Type): C; + + asOptional(type: Type): C | null; +} diff --git a/src/FileUploadMiddleware.ts b/src/FileUploadMiddleware.ts new file mode 100644 index 0000000..ba4946e --- /dev/null +++ b/src/FileUploadMiddleware.ts @@ -0,0 +1,35 @@ +import {IncomingForm} from "formidable"; +import Middleware from "./Middleware"; +import {NextFunction, Request, Response} from "express"; +import {FileError, ValidationBag} from "./db/Validator"; + +export default abstract class FileUploadMiddleware extends Middleware { + protected abstract makeForm(): IncomingForm; + + protected abstract getDefaultField(): string; + + public async handle(req: Request, res: Response, next: NextFunction): Promise { + const form = this.makeForm(); + try { + await new Promise((resolve, reject) => { + form.parse(req, (err, fields, files) => { + if (err) { + reject(err); + return; + } + req.body = fields; + req.files = files; + resolve(); + }); + }); + } catch (e) { + const bag = new ValidationBag(); + const fileError = new FileError(e); + fileError.thingName = this.getDefaultField(); + bag.addMessage(fileError); + next(bag); + return; + } + next(); + } +} diff --git a/src/HttpError.ts b/src/HttpError.ts index de03928..7071665 100644 --- a/src/HttpError.ts +++ b/src/HttpError.ts @@ -3,12 +3,12 @@ import {WrappingError} from "./Utils"; export abstract class HttpError extends WrappingError { public readonly instructions: string; - constructor(message: string, instructions: string, cause?: Error) { + protected constructor(message: string, instructions: string, cause?: Error) { super(message, cause); this.instructions = instructions; } - get name(): string { + public get name(): string { return this.constructor.name; } @@ -18,62 +18,83 @@ export abstract class HttpError extends WrappingError { export class BadRequestError extends HttpError { public readonly url: string; - constructor(message: string, instructions: string, url: string, cause?: Error) { + public constructor(message: string, instructions: string, url: string, cause?: Error) { super(message, instructions, cause); this.url = url; } - get errorCode(): number { + public get errorCode(): number { return 400; } } +export class UnauthorizedHttpError extends BadRequestError { + public constructor(message: string, url: string, cause?: Error) { + super(message, '', url, cause); + } + + public get errorCode(): number { + return 401; + } +} + export class ForbiddenHttpError extends BadRequestError { - constructor(thing: string, url: string, cause?: Error) { + public constructor(thing: string, url: string, cause?: Error) { super( `You don't have access to this ${thing}.`, `${url} doesn't belong to *you*.`, url, - cause + cause, ); } - get errorCode(): number { + public get errorCode(): number { return 403; } } export class NotFoundHttpError extends BadRequestError { - constructor(thing: string, url: string, cause?: Error) { + public constructor(thing: string, url: string, cause?: Error) { super( `${thing.charAt(0).toUpperCase()}${thing.substr(1)} not found.`, `${url} doesn't exist or was deleted.`, url, - cause + cause, ); } - get errorCode(): number { + public get errorCode(): number { return 404; } } +export class TooManyRequestsHttpError extends BadRequestError { + public constructor(retryIn: number, jailName: string, cause?: Error) { + super( + `You're making too many requests!`, + `We need some rest. Please retry in ${Math.floor(retryIn / 1000)} seconds.`, + jailName, + cause, + ); + } + + public get errorCode(): number { + return 429; + } +} + export class ServerError extends HttpError { - constructor(message: string, cause?: Error) { + public constructor(message: string, cause?: Error) { super(message, `Maybe you should contact us; see instructions below.`, cause); } - get errorCode(): number { + public get errorCode(): number { return 500; } } export class ServiceUnavailableHttpError extends ServerError { - constructor(message: string, cause?: Error) { - super(message, cause); - } - - get errorCode(): number { + public get errorCode(): number { return 503; } -} \ No newline at end of file +} diff --git a/src/Logger.ts b/src/Logger.ts index 9736e21..05ceee6 100644 --- a/src/Logger.ts +++ b/src/Logger.ts @@ -1,121 +1,40 @@ -import config from "config"; -import {v4 as uuid} from "uuid"; -import Log from "./models/Log"; +import {Logger as TsLogger} from "tslog"; +import {AsyncLocalStorage} from "async_hooks"; +import {RequestHandler} from "express"; +import {nanoid} from "nanoid"; -const LOG_LEVEL: LogLevelKeys = config.get('log_level'); -const DB_LOG_LEVEL: LogLevelKeys = config.get('db_log_level'); +const requestIdStorage: AsyncLocalStorage = new AsyncLocalStorage(); -export default class Logger { - public static silentError(error: Error, ...message: any[]): string { - return this.log('ERROR', message, error, true) || ''; - } +export const logger = new TsLogger({ + requestId: (): string => { + return requestIdStorage.getStore() as string; + }, + delimiter: '\t', + maskValuesOfKeys: [ + 'Authorization', + 'password', + 'password_confirmation', + 'secret', + ], + displayFunctionName: false, + displayFilePath: 'hidden', +}); - public static error(error: Error, ...message: any[]): string { - return this.log('ERROR', message, error) || ''; - } +export const loggingContextMiddleware: RequestHandler = (req, res, next) => { + requestIdStorage.run(nanoid(8), () => { + next(); + }); +}; - public static warn(...message: any[]) { - this.log('WARN', message); - } +export const preventContextCorruptionMiddleware = (delegate: RequestHandler): RequestHandler => ( + req, + res, + next, +) => { + const data = requestIdStorage.getStore() as string; - public static info(...message: any[]) { - this.log('INFO', message); - } - - public static debug(...message: any[]) { - this.log('DEBUG', message); - } - - public static dev(...message: any[]) { - this.log('DEV', message); - } - - private static log(level: LogLevelKeys, message: any[], error?: Error, silent: boolean = false): string | null { - const levelIndex = LogLevel[level]; - if (levelIndex <= LogLevel[LOG_LEVEL]) { - if (error) { - if (levelIndex > LogLevel.ERROR) this.warn(`Wrong log level ${level} with attached error.`); - } else { - if (levelIndex <= LogLevel.ERROR) this.warn(`No error attached with log level ${level}.`); - } - - const computedMsg = message.map(v => { - if (typeof v === 'string') { - return v; - } else { - return JSON.stringify(v, (key: string, value: any) => { - if (value instanceof Object) { - if (value.type === 'Buffer') { - return `Buffer<${Buffer.from(value.data).toString('hex')}>`; - } else if (value !== v) { - return `[object Object]`; - } - } - if (typeof value === 'string' && value.length > 96) { - return value.substr(0, 96) + '...'; - } - return value; - }, 4); - } - }).join(' '); - - const log = new Log({}); - log.setLevel(level); - log.message = computedMsg; - log.setError(error); - - let logID = Buffer.alloc(16); - uuid({}, logID); - log.setLogID(logID); - - - let output = `[${level}] `; - let pad = output.length; - if (levelIndex <= LogLevel[DB_LOG_LEVEL]) output += `${log.getLogID()} - `; - output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad)); - - switch (level) { - case "ERROR": - if (silent || !error) { - console.error(output); - } else { - console.error(output, error); - } - break; - case "WARN": - console.warn(output); - break; - case "INFO": - console.info(output); - break; - case "DEBUG": - case "DEV": - console.debug(output); - break; - } - - if (levelIndex <= LogLevel[DB_LOG_LEVEL]) { - log.save().catch(err => { - if (!silent && err.message.indexOf('ECONNREFUSED') < 0) { - console.error({save_err: err, error}); - } - }); - } - return log.getLogID(); - } - return null; - } - - private constructor() { - } -} - -export enum LogLevel { - ERROR, - WARN, - INFO, - DEBUG, - DEV, -} - -export type LogLevelKeys = keyof typeof LogLevel; + delegate(req, res, (err?: Error | 'router') => { + requestIdStorage.enterWith(data); + next(err); + }); +}; diff --git a/src/Mails.ts b/src/Mails.ts new file mode 100644 index 0000000..b1d619f --- /dev/null +++ b/src/Mails.ts @@ -0,0 +1,24 @@ +import config from "config"; +import {MailTemplate} from "./mail/Mail"; + +export const MAGIC_LINK_MAIL = new MailTemplate( + 'magic_link', + data => data.type === 'register' ? + 'Registration' : + 'Login magic link', +); + +export const ACCOUNT_REVIEW_NOTICE_MAIL_TEMPLATE: MailTemplate = new MailTemplate( + 'account_review_notice', + data => `Your account was ${data.approved ? 'approved' : 'rejected'}.`, +); + +export const PENDING_ACCOUNT_REVIEW_MAIL_TEMPLATE: MailTemplate = new MailTemplate( + 'pending_account_review', + () => `A new account is pending review on ${config.get('app.name')}`, +); + +export const ADD_EMAIL_MAIL_TEMPLATE: MailTemplate = new MailTemplate( + 'add_email', + (data) => `Add ${data.email} address to your ${config.get('app.name')} account.`, +); diff --git a/src/Middleware.ts b/src/Middleware.ts new file mode 100644 index 0000000..a46cf3a --- /dev/null +++ b/src/Middleware.ts @@ -0,0 +1,33 @@ +import {RequestHandler} from "express"; +import {NextFunction, Request, Response} from "express-serve-static-core"; +import Application from "./Application"; +import {Type} from "./Utils"; + +export default abstract class Middleware { + public constructor( + protected readonly app: Application, + ) { + } + + + protected abstract handle(req: Request, res: Response, next: NextFunction): Promise; + + public getRequestHandler(): RequestHandler { + return async (req, res, next): Promise => { + try { + if (req.middlewares.find(m => m.constructor === this.constructor)) { + next(); + } else { + req.middlewares.push(this); + return await this.handle(req, res, next); + } + } catch (e) { + next(e); + } + }; + } +} + +export interface MiddlewareType extends Type { + new(app: Application): M; +} diff --git a/src/Pagination.ts b/src/Pagination.ts index 1cb0539..50055d9 100644 --- a/src/Pagination.ts +++ b/src/Pagination.ts @@ -6,7 +6,7 @@ export default class Pagination { public readonly perPage: number; public readonly totalCount: number; - constructor(models: T[], page: number, perPage: number, totalCount: number) { + public constructor(models: T[], page: number, perPage: number, totalCount: number) { this.models = models; this.page = page; this.perPage = perPage; @@ -21,4 +21,4 @@ export default class Pagination { return this.models.length >= this.perPage && this.page * this.perPage < this.totalCount; } -} \ No newline at end of file +} diff --git a/src/SecurityError.ts b/src/SecurityError.ts new file mode 100644 index 0000000..832c734 --- /dev/null +++ b/src/SecurityError.ts @@ -0,0 +1,8 @@ +export default class SecurityError implements Error { + public readonly name: string = 'SecurityError'; + public readonly message: string; + + public constructor(message: string) { + this.message = message; + } +} diff --git a/src/TestApp.ts b/src/TestApp.ts new file mode 100644 index 0000000..de24b16 --- /dev/null +++ b/src/TestApp.ts @@ -0,0 +1,122 @@ +import Application from "../src/Application"; +import Migration, {MigrationType} from "../src/db/Migration"; +import ExpressAppComponent from "../src/components/ExpressAppComponent"; +import RedisComponent from "../src/components/RedisComponent"; +import MysqlComponent from "../src/components/MysqlComponent"; +import NunjucksComponent from "../src/components/NunjucksComponent"; +import LogRequestsComponent from "../src/components/LogRequestsComponent"; +import MailComponent from "../src/components/MailComponent"; +import SessionComponent from "../src/components/SessionComponent"; +import AuthComponent from "../src/auth/AuthComponent"; +import FormHelperComponent from "../src/components/FormHelperComponent"; +import ServeStaticDirectoryComponent from "../src/components/ServeStaticDirectoryComponent"; +import {Express} from "express"; +import MagicLinkAuthMethod from "../src/auth/magic_link/MagicLinkAuthMethod"; +import PasswordAuthMethod from "../src/auth/password/PasswordAuthMethod"; +import {MAGIC_LINK_MAIL} from "./Mails"; +import CreateMigrationsTable from "./migrations/CreateMigrationsTable"; +import CreateUsersAndUserEmailsTableMigration from "./auth/migrations/CreateUsersAndUserEmailsTableMigration"; +import CreateMagicLinksTableMigration from "./auth/magic_link/CreateMagicLinksTableMigration"; +import AuthController from "./auth/AuthController"; +import MagicLinkWebSocketListener from "./auth/magic_link/MagicLinkWebSocketListener"; +import MagicLinkController from "./auth/magic_link/MagicLinkController"; +import AddPasswordToUsersMigration from "./auth/password/AddPasswordToUsersMigration"; +import AddNameToUsersMigration from "./auth/migrations/AddNameToUsersMigration"; +import CsrfProtectionComponent from "./components/CsrfProtectionComponent"; +import MailController from "./mail/MailController"; +import WebSocketServerComponent from "./components/WebSocketServerComponent"; +import Controller from "./Controller"; +import AccountController from "./auth/AccountController"; +import MakeMagicLinksSessionNotUniqueMigration from "./auth/magic_link/MakeMagicLinksSessionNotUniqueMigration"; +import AddUsedToMagicLinksMigration from "./auth/magic_link/AddUsedToMagicLinksMigration"; +import packageJson = require('../package.json'); +import PreviousUrlComponent from "./components/PreviousUrlComponent"; + +export const MIGRATIONS = [ + CreateMigrationsTable, + CreateUsersAndUserEmailsTableMigration, + AddPasswordToUsersMigration, + CreateMagicLinksTableMigration, + AddNameToUsersMigration, + MakeMagicLinksSessionNotUniqueMigration, + AddUsedToMagicLinksMigration, +]; + +export default class TestApp extends Application { + private readonly addr: string; + private readonly port: number; + + public constructor(addr: string, port: number) { + super(packageJson.version, true); + this.addr = addr; + this.port = port; + } + + protected getMigrations(): MigrationType[] { + return MIGRATIONS; + } + + protected async init(): Promise { + this.registerComponents(); + this.registerWebSocketListeners(); + this.registerControllers(); + } + + protected registerComponents(): void { + // Base + this.use(new ExpressAppComponent(this.addr, this.port)); + this.use(new LogRequestsComponent()); + + // Static files + this.use(new ServeStaticDirectoryComponent('public')); + + // Dynamic views and routes + this.use(new NunjucksComponent(['test/views', 'views'])); + this.use(new PreviousUrlComponent()); + + // Services + this.use(new MysqlComponent()); + this.use(new MailComponent()); + + // Session + this.use(new RedisComponent()); + this.use(new SessionComponent(this.as(RedisComponent))); + + // Utils + this.use(new FormHelperComponent()); + + // Middlewares + this.use(new CsrfProtectionComponent()); + + // Auth + this.use(new AuthComponent(this, new MagicLinkAuthMethod(this, MAGIC_LINK_MAIL), new PasswordAuthMethod(this))); + + // WebSocket server + this.use(new WebSocketServerComponent(this, this.as(ExpressAppComponent), this.as(RedisComponent))); + } + + protected registerWebSocketListeners(): void { + this.use(new MagicLinkWebSocketListener()); + } + + protected registerControllers(): void { + this.use(new MailController()); + this.use(new AuthController()); + this.use(new AccountController()); + + this.use(new MagicLinkController(this.as>(MagicLinkWebSocketListener))); + + // Special home controller + this.use(new class extends Controller { + public routes(): void { + this.get('/', (req, res) => { + res.render('home'); + }, 'home'); + } + }()); + } + + public getExpressApp(): Express { + return this.as(ExpressAppComponent).getExpressApp(); + } +} diff --git a/src/Throttler.ts b/src/Throttler.ts new file mode 100644 index 0000000..863c467 --- /dev/null +++ b/src/Throttler.ts @@ -0,0 +1,93 @@ +import {TooManyRequestsHttpError} from "./HttpError"; +import {logger} from "./Logger"; + +export default class Throttler { + private static readonly throttles: Record = {}; + + /** + * Throttle function; will throw a TooManyRequestsHttpError when the threshold is reached. + * + * This throttle is adaptive: it will slowly decrease (linear) until it reaches 0 after {@param resetPeriod} ms. + * Threshold will hold for {@param holdPeriod} ms. + * + * @param action a unique action name (can be used multiple times, but it'll account for a single action). + * @param max how many times this action can be triggered per id. + * @param resetPeriod after how much time in ms the throttle will reach 0. + * @param id an identifier of who triggered the action. + * @param holdPeriod time in ms after each call before the threshold begins to decrease. + * @param jailPeriod time in ms for which the throttle will throw when it is triggered. + */ + public static throttle( + action: string, + max: number, + resetPeriod: number, + id: string, + holdPeriod: number = 100, + jailPeriod: number = 30 * 1000, + ): void { + let throttle = this.throttles[action]; + if (!throttle) + throttle = this.throttles[action] = new Throttle(action, max, resetPeriod, holdPeriod, jailPeriod); + throttle.trigger(id); + } + + private constructor() { + // Disable constructor + } +} + +class Throttle { + private readonly jailName: string; + private readonly max: number; + private readonly resetPeriod: number; + private readonly holdPeriod: number; + private readonly jailPeriod: number; + private readonly triggers: Record = {}; + + public constructor(jailName: string, max: number, resetPeriod: number, holdPeriod: number, jailPeriod: number) { + this.jailName = jailName; + this.max = max; + this.resetPeriod = resetPeriod; + this.holdPeriod = holdPeriod; + this.jailPeriod = jailPeriod; + } + + + public trigger(id: string) { + let trigger = this.triggers[id]; + if (!trigger) trigger = this.triggers[id] = {count: 0}; + + const currentDate = new Date().getTime(); + + if (trigger.jailed && currentDate - trigger.jailed < this.jailPeriod) + return this.throw(trigger.jailed + this.jailPeriod - currentDate); + + if (trigger.lastTrigger) { + let timeDiff = currentDate - trigger.lastTrigger; + if (timeDiff > this.holdPeriod) { + timeDiff -= this.holdPeriod; + trigger.count = Math.floor(Math.min(trigger.count, (this.max + 1) * (1 - timeDiff / this.resetPeriod))); + } + } + + trigger.count++; + trigger.lastTrigger = currentDate; + + if (trigger.count > this.max) { + trigger.jailed = currentDate; + + const unjailedIn = trigger.jailed + this.jailPeriod - currentDate; + logger.info(`Jail ${this.jailName} triggered by ${id} and will be unjailed in ${unjailedIn}ms.`); + + return this.throw(unjailedIn); + } + } + + protected throw(unjailedIn: number) { + throw new TooManyRequestsHttpError(unjailedIn, this.jailName); + } +} diff --git a/src/Utils.ts b/src/Utils.ts index 99bbfdd..53d0891 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -1,5 +1,3 @@ -import * as crypto from "crypto"; - export async function sleep(ms: number): Promise { return await new Promise(resolve => { setTimeout(() => resolve(), ms); @@ -18,22 +16,31 @@ export abstract class WrappingError extends Error { } } - get name(): string { + public get name(): string { return this.constructor.name; } } -export function cryptoRandomDictionary(size: number, dictionary: string): string { - const randomBytes = crypto.randomBytes(size); - const output = new Array(size); +export type Type = { new(...args: never[]): T }; - for (let i = 0; i < size; i++) { - output[i] = dictionary[Math.floor((randomBytes[i] / 255) * dictionary.length)]; +export function bufferToUuid(buffer: Buffer): string { + const chars = buffer.toString('hex'); + let out = ''; + let i = 0; + for (const l of [8, 4, 4, 4, 12]) { + if (i > 0) out += '-'; + out += chars.substr(i, l); + i += l; } - - return output.join(''); + return out; } -export interface Type extends Function { - new(...args: any[]): T -} \ No newline at end of file +export function getMethods(obj: T): string[] { + const properties = new Set(); + let currentObj: T | unknown = obj; + do { + Object.getOwnPropertyNames(currentObj).map(item => properties.add(item)); + currentObj = Object.getPrototypeOf(currentObj); + } while (currentObj); + return [...properties.keys()].filter(item => typeof obj[item] === 'function'); +} diff --git a/src/WebSocketListener.ts b/src/WebSocketListener.ts index abe1ef9..b3702d8 100644 --- a/src/WebSocketListener.ts +++ b/src/WebSocketListener.ts @@ -1,8 +1,24 @@ import WebSocket from "ws"; import {IncomingMessage} from "http"; +import Application from "./Application"; +import {Session} from "express-session"; + +export default abstract class WebSocketListener { + private app!: T; + + public init(app: T): void { + this.app = app; + } + + protected getApp(): T { + return this.app; + } -export default abstract class WebSocketListener { public abstract path(): string; - public abstract async handle(socket: WebSocket, request: IncomingMessage, session: Express.SessionData): Promise; -} \ No newline at end of file + public abstract handle( + socket: WebSocket, + request: IncomingMessage, + session: Session | null, + ): Promise; +} diff --git a/src/auth/AccountController.ts b/src/auth/AccountController.ts new file mode 100644 index 0000000..a68d0e4 --- /dev/null +++ b/src/auth/AccountController.ts @@ -0,0 +1,145 @@ +import Controller from "../Controller"; +import {RequireAuthMiddleware} from "./AuthComponent"; +import {Request, Response} from "express"; +import {BadRequestError, ForbiddenHttpError, NotFoundHttpError} from "../HttpError"; +import config from "config"; +import Validator, {EMAIL_REGEX, InvalidFormatValidationError} from "../db/Validator"; +import UserPasswordComponent from "./password/UserPasswordComponent"; +import User from "./models/User"; +import ModelFactory from "../db/ModelFactory"; +import UserEmail from "./models/UserEmail"; +import MagicLinkController from "./magic_link/MagicLinkController"; +import {MailTemplate} from "../mail/Mail"; +import {ADD_EMAIL_MAIL_TEMPLATE} from "../Mails"; +import AuthMagicLinkActionType from "./magic_link/AuthMagicLinkActionType"; + +export default class AccountController extends Controller { + private readonly addEmailMailTemplate: MailTemplate; + + public constructor(addEmailMailTemplate: MailTemplate = ADD_EMAIL_MAIL_TEMPLATE) { + super(); + this.addEmailMailTemplate = addEmailMailTemplate; + } + + public getRoutesPrefix(): string { + return '/account'; + } + + public routes(): void { + this.get('/', this.getAccount, 'account', RequireAuthMiddleware); + + if (ModelFactory.get(User).hasComponent(UserPasswordComponent)) { + this.post('/change-password', this.postChangePassword, 'change-password', RequireAuthMiddleware); + } + + this.post('/add-email', this.addEmail, 'add-email', RequireAuthMiddleware); + this.post('/set-main-email', this.postSetMainEmail, 'set-main-email', RequireAuthMiddleware); + this.post('/remove-email', this.postRemoveEmail, 'remove-email', RequireAuthMiddleware); + } + + protected async getAccount(req: Request, res: Response): Promise { + const user = req.as(RequireAuthMiddleware).getUser(); + + res.render('auth/account', { + main_email: await user.mainEmail.get(), + emails: await user.emails.get(), + display_email_warning: config.get('app.display_email_warning'), + has_password: user.asOptional(UserPasswordComponent)?.hasPassword(), + }); + } + + protected async postChangePassword(req: Request, res: Response): Promise { + const validationMap = { + 'new_password': new Validator().defined(), + 'new_password_confirmation': new Validator().sameAs('new_password', req.body.new_password), + }; + await Validator.validate(validationMap, req.body); + const user = req.as(RequireAuthMiddleware).getUser(); + const passwordComponent = user.as(UserPasswordComponent); + if (passwordComponent.hasPassword() && !await passwordComponent.verifyPassword(req.body.current_password)) { + req.flash('error', 'Invalid current password.'); + res.redirect(Controller.route('account')); + return; + } + + await passwordComponent.setPassword(req.body.new_password, 'new_password'); + await user.save(); + + req.flash('success', 'Password changed successfully.'); + res.redirect(Controller.route('account')); + } + + + protected async addEmail(req: Request, res: Response): Promise { + await Validator.validate({ + email: new Validator().defined().regexp(EMAIL_REGEX), + }, req.body); + + const email = req.body.email; + + // Existing email + if (await UserEmail.select().where('email', email).first()) { + const error = new InvalidFormatValidationError('You already have this email.'); + error.thingName = 'email'; + throw error; + } + + await MagicLinkController.sendMagicLink( + this.getApp(), + req.getSession().id, + AuthMagicLinkActionType.ADD_EMAIL, + Controller.route('account'), + email, + this.addEmailMailTemplate, + { + email: email, + }, + ); + + res.redirect(Controller.route('magic_link_lobby', undefined, { + redirect_uri: Controller.route('account'), + })); + } + + protected async postSetMainEmail(req: Request, res: Response): Promise { + if (!req.body.id) + throw new BadRequestError('Missing id field', 'Check form parameters.', req.url); + + const user = req.as(RequireAuthMiddleware).getUser(); + + const userEmail = await UserEmail.getById(req.body.id); + if (!userEmail) + throw new NotFoundHttpError('email', req.url); + if (userEmail.user_id !== user.id) + throw new ForbiddenHttpError('email', req.url); + if (userEmail.id === user.main_email_id) + throw new BadRequestError('This address is already your main address', + 'Try refreshing the account page.', req.url); + + user.main_email_id = userEmail.id; + await user.save(); + + req.flash('success', 'This email was successfully set as your main address.'); + res.redirect(Controller.route('account')); + } + + protected async postRemoveEmail(req: Request, res: Response): Promise { + if (!req.body.id) + throw new BadRequestError('Missing id field', 'Check form parameters.', req.url); + + const user = req.as(RequireAuthMiddleware).getUser(); + + const userEmail = await UserEmail.getById(req.body.id); + if (!userEmail) + throw new NotFoundHttpError('email', req.url); + if (userEmail.user_id !== user.id) + throw new ForbiddenHttpError('email', req.url); + if (userEmail.id === user.main_email_id) + throw new BadRequestError('Cannot remove main email address', 'Try refreshing the account page.', req.url); + + await userEmail.delete(); + + req.flash('success', 'This email was successfully removed from your account.'); + res.redirect(Controller.route('account')); + } +} diff --git a/src/auth/AuthComponent.ts b/src/auth/AuthComponent.ts new file mode 100644 index 0000000..552959b --- /dev/null +++ b/src/auth/AuthComponent.ts @@ -0,0 +1,136 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {NextFunction, Request, Response} from "express"; +import AuthGuard from "./AuthGuard"; +import Controller from "../Controller"; +import {ForbiddenHttpError} from "../HttpError"; +import Middleware from "../Middleware"; +import User from "./models/User"; +import Application from "../Application"; +import AuthMethod from "./AuthMethod"; +import AuthProof from "./AuthProof"; + +export default class AuthComponent extends ApplicationComponent { + private readonly authGuard: AuthGuard; + + public constructor(app: Application, ...authMethods: AuthMethod>[]) { + super(); + this.authGuard = new AuthGuard(app, ...authMethods); + } + + public async init(): Promise { + this.use(AuthMiddleware); + } + + public getAuthGuard(): AuthGuard { + return this.authGuard; + } +} + +export class AuthMiddleware extends Middleware { + private authGuard?: AuthGuard; + private user: User | null = null; + + protected async handle(req: Request, res: Response, next: NextFunction): Promise { + this.authGuard = this.app.as(AuthComponent).getAuthGuard(); + + const proofs = await this.authGuard.getProofsForSession(req.getSession()); + if (proofs.length > 0) { + this.user = await proofs[0].getResource(); + res.locals.user = this.user; + } + + next(); + } + + public getUser(): User | null { + return this.user; + } + + public getAuthGuard(): AuthGuard { + if (!this.authGuard) throw new Error('AuthGuard was not initialized.'); + return this.authGuard; + } +} + +export class RequireRequestAuthMiddleware extends Middleware { + private user?: User; + + protected async handle(req: Request, res: Response, next: NextFunction): Promise { + const proofs = await req.as(AuthMiddleware).getAuthGuard().getProofsForRequest(req); + const user = await proofs[0]?.getResource(); + if (user) { + this.user = user; + next(); + return; + } + + req.flash('error', `You must be logged in to access ${req.url}.`); + res.redirect(Controller.route('auth', undefined, { + redirect_uri: req.url, + })); + } + + public getUser(): User { + if (!this.user) throw new Error('user not initialized.'); + return this.user; + } +} + +export class RequireAuthMiddleware extends Middleware { + private user?: User; + + protected async handle(req: Request, res: Response, next: NextFunction): Promise { + const authGuard = req.as(AuthMiddleware).getAuthGuard(); + // Via request + + let proofs = await authGuard.getProofsForRequest(req); + let user = await proofs[0]?.getResource(); + if (user) { + this.user = user; + next(); + return; + } + + // Via session + proofs = await authGuard.getProofsForSession(req.getSession()); + user = await proofs[0]?.getResource(); + if (user) { + this.user = user; + next(); + return; + } + + req.flash('error', `You must be logged in to access ${req.url}.`); + res.redirect(Controller.route('auth', undefined, { + redirect_uri: req.url, + })); + } + + public getUser(): User { + if (!this.user) throw new Error('user not initialized.'); + return this.user; + } +} + +export class RequireGuestMiddleware extends Middleware { + protected async handle(req: Request, res: Response, next: NextFunction): Promise { + const proofs = await req.as(AuthMiddleware).getAuthGuard().getProofsForSession(req.getSession()); + if (proofs.length > 0) { + res.redirect(Controller.route('home')); + return; + } + + next(); + } +} + +export class RequireAdminMiddleware extends Middleware { + protected async handle(req: Request, res: Response, next: NextFunction): Promise { + const user = req.as(AuthMiddleware).getUser(); + if (!user || !user.is_admin) { + throw new ForbiddenHttpError('secret tool', req.url); + } + + next(); + } +} diff --git a/src/auth/AuthController.ts b/src/auth/AuthController.ts new file mode 100644 index 0000000..81fd255 --- /dev/null +++ b/src/auth/AuthController.ts @@ -0,0 +1,129 @@ +import Controller from "../Controller"; +import {NextFunction, Request, Response} from "express"; +import AuthComponent, {AuthMiddleware, RequireAuthMiddleware, RequireGuestMiddleware} from "./AuthComponent"; +import {BadRequestError} from "../HttpError"; +import ModelFactory from "../db/ModelFactory"; +import User from "./models/User"; +import UserPasswordComponent from "./password/UserPasswordComponent"; +import UserNameComponent from "./models/UserNameComponent"; +import {UnknownRelationValidationError} from "../db/Validator"; +import AuthMethod from "./AuthMethod"; +import AuthProof from "./AuthProof"; + +export default class AuthController extends Controller { + public getRoutesPrefix(): string { + return '/auth'; + } + + public routes(): void { + this.post('/logout', this.postLogout, 'logout', RequireAuthMiddleware); + + this.use(async (req, res, next) => { + const authGuard = this.getApp().as(AuthComponent).getAuthGuard(); + if (await authGuard.interruptAuth(req, res)) return; + next(); + }); + + this.get('/', this.getAuth, 'auth', RequireGuestMiddleware); + this.post('/login', this.postLogin, 'login', RequireGuestMiddleware); + this.post('/register', this.postRegister, 'register', RequireGuestMiddleware); + } + + protected async getAuth(req: Request, res: Response, _next: NextFunction): Promise { + const authGuard = this.getApp().as(AuthComponent).getAuthGuard(); + + const userModelFactory = ModelFactory.get(User); + const hasUsername = userModelFactory.hasComponent(UserNameComponent); + res.render('auth/auth', { + auth_methods: authGuard.getAuthMethodNames(), + has_username: hasUsername, + register_with_password: hasUsername && userModelFactory.hasComponent(UserPasswordComponent), + }); + } + + protected async postLogin(req: Request, res: Response): Promise { + return await this.handleAuth(req, res, false); + } + + protected async postRegister(req: Request, res: Response): Promise { + return await this.handleAuth(req, res, true); + } + + protected async handleAuth(req: Request, res: Response, isRegistration: boolean): Promise { + if (isRegistration && !req.body.auth_method) { + throw new BadRequestError('Cannot register without specifying desired auth_method.', + 'Please specify auth_method.', req.url); + } + + const authGuard = this.getApp().as(AuthComponent).getAuthGuard(); + + const identifier = req.body.identifier; + if (!identifier) throw new BadRequestError('Identifier not specified.', 'Please try again.', req.originalUrl); + + // Get requested auth method + if (req.body.auth_method) { + const method = await authGuard.getAuthMethodByName(req.body.auth_method); + if (!method) { + throw new BadRequestError('Invalid auth method: ' + req.body.auth_method, + 'Available methods are: ' + authGuard.getAuthMethodNames(), req.url); + } + + // Register + if (isRegistration) return await method.attemptRegister(req, res, identifier); + + const user = await method.findUserByIdentifier(identifier); + + // Redirect to registration if user not found + if (!user) return await this.redirectToRegistration(req, res, identifier); + + // Login + return await method.attemptLogin(req, res, user); + } + + const methods = await authGuard.getAuthMethodsByIdentifier(identifier); + + // Redirect to registration if user not found + if (methods.length === 0) return await this.redirectToRegistration(req, res, identifier); + + // Choose best matching method + let user: User | null = null; + let method: AuthMethod> | null = null; + let weight = -1; + + for (const entry of methods) { + const methodWeight = entry.method.getWeightForRequest(req); + if (methodWeight > weight) { + user = entry.user; + method = entry.method; + weight = methodWeight; + } + } + + if (!method || !user) ({method, user} = methods[0]); // Default to first method + + // Login + return await method.attemptLogin(req, res, user); + } + + protected async postLogout(req: Request, res: Response, _next: NextFunction): Promise { + const userId = typeof req.body.user_id === 'string' ? parseInt(req.body.user_id) : null; + + const proofs = await req.as(AuthMiddleware).getAuthGuard().getProofs(req); + + for (const proof of proofs) { + if (userId === null || (await proof.getResource())?.id === userId) { + await proof.revoke(); + } + } + + req.flash('success', 'Successfully logged out.'); + res.redirect(req.getIntendedUrl() || '/'); + } + + protected async redirectToRegistration(req: Request, res: Response, identifier: string): Promise { + const error = new UnknownRelationValidationError(User.table, 'identifier'); + error.thingName = 'identifier'; + error.value = identifier; + throw error; + } +} diff --git a/src/auth/AuthGuard.ts b/src/auth/AuthGuard.ts new file mode 100644 index 0000000..e13b8eb --- /dev/null +++ b/src/auth/AuthGuard.ts @@ -0,0 +1,187 @@ +import AuthProof from "./AuthProof"; +import MysqlConnectionManager from "../db/MysqlConnectionManager"; +import User from "./models/User"; +import {Connection} from "mysql"; +import {Request, Response} from "express"; +import {PENDING_ACCOUNT_REVIEW_MAIL_TEMPLATE} from "../Mails"; +import Mail from "../mail/Mail"; +import Controller from "../Controller"; +import config from "config"; +import Application from "../Application"; +import NunjucksComponent from "../components/NunjucksComponent"; +import AuthMethod from "./AuthMethod"; +import {Session, SessionData} from "express-session"; + +export default class AuthGuard { + private readonly authMethods: AuthMethod>[]; + + public constructor( + private readonly app: Application, + ...authMethods: AuthMethod>[] + ) { + this.authMethods = authMethods; + } + + public async interruptAuth(req: Request, res: Response): Promise { + for (const method of this.authMethods) { + if (method.interruptAuth && await method.interruptAuth(req, res)) return true; + } + + return false; + } + + public getAuthMethodByName(authMethodName: string): AuthMethod> | null { + return this.authMethods.find(m => m.getName() === authMethodName) || null; + } + + public getAuthMethodNames(): string[] { + return this.authMethods.map(m => m.getName()); + } + + public getRegistrationMethod(): AuthMethod> { + return this.authMethods[0]; + } + + public async getAuthMethodsByIdentifier( + identifier: string, + ): Promise<{ user: User, method: AuthMethod> }[]> { + const methods = []; + for (const method of this.authMethods) { + const user = await method.findUserByIdentifier(identifier); + if (user) methods.push({user, method}); + } + return methods; + } + + public async getProofs(req: Request): Promise[]> { + const proofs = []; + if (req.getSessionOptional()) { + proofs.push(...await this.getProofsForSession(req.session)); + } + proofs.push(...await this.getProofsForRequest(req)); + return proofs; + } + + public async getProofsForSession(session: Session & Partial): Promise[]> { + if (!session.isAuthenticated) return []; + + const proofs = []; + for (const method of this.authMethods) { + if (method.getProofsForSession) { + const methodProofs = await method.getProofsForSession(session); + for (const proof of methodProofs) { + if (!await proof.isValid() || !await proof.isAuthorized()) { + await proof.revoke(); + } else { + proofs.push(proof); + } + } + } + } + + if (proofs.length === 0) { + session.isAuthenticated = false; + session.persistent = false; + } + + return proofs; + } + + public async getProofsForRequest(req: Request): Promise[]> { + const proofs = []; + for (const method of this.authMethods) { + if (method.getProofsForRequest) { + const methodProofs = await method.getProofsForRequest(req); + for (const proof of methodProofs) { + if (!await proof.isValid() || !await proof.isAuthorized()) { + await proof.revoke(); + } else { + proofs.push(proof); + } + } + } + } + + return proofs; + } + + public async authenticateOrRegister( + session: Session & Partial, + proof: AuthProof, + persistSession: boolean, + onLogin?: (user: User) => Promise, + beforeRegister?: (connection: Connection, user: User) => Promise, + afterRegister?: (connection: Connection, user: User) => Promise, + ): Promise { + if (!await proof.isValid()) throw new InvalidAuthProofError(); + if (!await proof.isAuthorized()) throw new UnauthorizedAuthProofError(); + + let user = await proof.getResource(); + + // Register if user doesn't exist + if (!user) { + const callbacks: RegisterCallback[] = []; + + user = await MysqlConnectionManager.wrapTransaction(async connection => { + const user = User.create({}); + if (beforeRegister) { + (await beforeRegister(connection, user)).forEach(c => callbacks.push(c)); + } + await user.save(connection, c => callbacks.push(c)); + if (afterRegister) { + (await afterRegister(connection, user)).forEach(c => callbacks.push(c)); + } + return user; + }); + + for (const callback of callbacks) { + await callback(); + } + + if (!user.isApproved()) { + await new Mail(this.app.as(NunjucksComponent).getEnvironment(), PENDING_ACCOUNT_REVIEW_MAIL_TEMPLATE, { + username: (await user.mainEmail.get())?.getOrFail('email'), + link: config.get('public_url') + Controller.route('accounts-approval'), + }).send(config.get('app.contact_email')); + } + } + + // Don't login if user isn't approved + if (!user.isApproved()) { + throw new PendingApprovalAuthError(); + } + + // Login + session.isAuthenticated = true; + session.persistent = persistSession; + if (onLogin) await onLogin(user); + + return user; + } +} + +export class AuthError extends Error { +} + +export class AuthProofError extends AuthError { +} + +export class InvalidAuthProofError extends AuthProofError { + public constructor() { + super('Invalid auth proof.'); + } +} + +export class UnauthorizedAuthProofError extends AuthProofError { + public constructor() { + super('Unauthorized auth proof.'); + } +} + +export class PendingApprovalAuthError extends AuthError { + public constructor() { + super(`User is not approved.`); + } +} + +export type RegisterCallback = () => Promise; diff --git a/src/auth/AuthMethod.ts b/src/auth/AuthMethod.ts new file mode 100644 index 0000000..fa0179a --- /dev/null +++ b/src/auth/AuthMethod.ts @@ -0,0 +1,35 @@ +import User from "./models/User"; +import AuthProof from "./AuthProof"; +import {Request, Response} from "express"; +import {Session} from "express-session"; + + +export default interface AuthMethod

> { + /** + * @return A unique name. + */ + getName(): string; + + /** + * Used for automatic auth method detection. Won't affect forced auth method. + * + * @return {@code 0} if the request is not conform to this auth method, otherwise the exact count of matching + * fields. + */ + getWeightForRequest(req: Request): number; + + findUserByIdentifier(identifier: string): Promise; + + getProofsForSession?(session: Session): Promise; + + getProofsForRequest?(req: Request): Promise; + + /** + * @return {@code true} if interrupted, {@code false} otherwise. + */ + interruptAuth?(req: Request, res: Response): Promise; + + attemptLogin(req: Request, res: Response, user: User): Promise; + + attemptRegister(req: Request, res: Response, identifier: string): Promise; +} diff --git a/src/auth/AuthProof.ts b/src/auth/AuthProof.ts new file mode 100644 index 0000000..960d119 --- /dev/null +++ b/src/auth/AuthProof.ts @@ -0,0 +1,41 @@ +/** + * This class is most commonly used for authentication. It can be more generically used to represent a verification + * state of whether a given resource is owned by a session. + * + * Any auth system should consider this auth proof valid if and only if both {@code isValid()} and + * {@code isAuthorized()} both return {@code true}. + * + * @type The resource type this AuthProof authorizes. + */ +export default interface AuthProof { + /** + * Is this auth proof valid in time (and context)? + * + * For example, it can return true for an initial short validity time period then false, and increase that time + * period if {@code isAuthorized()} returns true. + */ + isValid(): Promise; + + /** + * Was this proof authorized? + * + * Return true once the session is proven to own the associated resource. + */ + isAuthorized(): Promise; + + /** + * Retrieve the resource this auth proof is supposed to authorize. + * If this resource doesn't exist yet, return {@code null}. + */ + getResource(): Promise; + + /** + * Manually revokes this authentication proof. Once this method is called, all of the following must be true: + * - {@code isAuthorized} returns {@code false} + * - There is no way to re-authorize this proof (i.e. {@code isAuthorized} can never return {@code true} again) + * + * Additionally, this method should delete any stored data that could lead to restoration of this AuthProof + * instance. + */ + revoke(): Promise; +} diff --git a/src/auth/magic_link/AddUsedToMagicLinksMigration.ts b/src/auth/magic_link/AddUsedToMagicLinksMigration.ts new file mode 100644 index 0000000..3e7f639 --- /dev/null +++ b/src/auth/magic_link/AddUsedToMagicLinksMigration.ts @@ -0,0 +1,12 @@ +import Migration from "../../db/Migration"; + +export default class AddUsedToMagicLinksMigration extends Migration { + public async install(): Promise { + await this.query(`ALTER TABLE magic_links + ADD COLUMN used BOOLEAN NOT NULL`); + } + + public async rollback(): Promise { + await this.query('ALTER TABLE magic_links DROP COLUMN IF EXISTS used'); + } +} diff --git a/src/auth/magic_link/AuthMagicLinkActionType.ts b/src/auth/magic_link/AuthMagicLinkActionType.ts new file mode 100644 index 0000000..7e907cf --- /dev/null +++ b/src/auth/magic_link/AuthMagicLinkActionType.ts @@ -0,0 +1,5 @@ +export default { + LOGIN: 'login', + REGISTER: 'register', + ADD_EMAIL: 'add_email', +}; diff --git a/src/auth/magic_link/CreateMagicLinksTableMigration.ts b/src/auth/magic_link/CreateMagicLinksTableMigration.ts new file mode 100644 index 0000000..680bf5a --- /dev/null +++ b/src/auth/magic_link/CreateMagicLinksTableMigration.ts @@ -0,0 +1,29 @@ +import Migration from "../../db/Migration"; +import ModelFactory from "../../db/ModelFactory"; +import MagicLink from "../models/MagicLink"; + +export default class CreateMagicLinksTableMigration extends Migration { + public async install(): Promise { + await this.query(`CREATE TABLE magic_links + ( + id INT NOT NULL AUTO_INCREMENT, + session_id CHAR(32) UNIQUE NOT NULL, + email VARCHAR(254) NOT NULL, + token CHAR(96) NOT NULL, + action_type VARCHAR(64) NOT NULL, + original_url VARCHAR(1745) NOT NULL, + generated_at DATETIME NOT NULL, + authorized BOOLEAN NOT NULL, + PRIMARY KEY (id) + )`); + } + + public async rollback(): Promise { + await this.query('DROP TABLE magic_links'); + } + + public registerModels(): void { + ModelFactory.register(MagicLink); + } + +} diff --git a/src/auth/magic_link/MagicLinkAuthMethod.ts b/src/auth/magic_link/MagicLinkAuthMethod.ts new file mode 100644 index 0000000..9048594 --- /dev/null +++ b/src/auth/magic_link/MagicLinkAuthMethod.ts @@ -0,0 +1,125 @@ +import AuthMethod from "../AuthMethod"; +import {Request, Response} from "express"; +import User from "../models/User"; +import UserEmail from "../models/UserEmail"; +import MagicLink from "../models/MagicLink"; +import {WhereTest} from "../../db/ModelQuery"; +import Controller from "../../Controller"; +import geoip from "geoip-lite"; +import MagicLinkController from "./MagicLinkController"; +import Application from "../../Application"; +import {MailTemplate} from "../../mail/Mail"; +import AuthMagicLinkActionType from "./AuthMagicLinkActionType"; +import Validator, {EMAIL_REGEX} from "../../db/Validator"; +import ModelFactory from "../../db/ModelFactory"; +import UserNameComponent from "../models/UserNameComponent"; +import {Session} from "express-session"; + +export default class MagicLinkAuthMethod implements AuthMethod { + public constructor( + protected readonly app: Application, + protected readonly magicLinkMailTemplate: MailTemplate, + ) { + } + + public getName(): string { + return 'magic_link'; + } + + public getWeightForRequest(req: Request): number { + return !req.body.identifier || !EMAIL_REGEX.test(req.body.identifier) ? + 0 : + 1; + } + + public async findUserByIdentifier(identifier: string): Promise { + return (await UserEmail.select() + .with('user.mainEmail') + .where('email', identifier) + .first())?.user.getOrFail() || null; + } + + public async getProofsForSession(session: Session): Promise { + return await MagicLink.select() + .where('session_id', session.id) + .where('action_type', [AuthMagicLinkActionType.LOGIN, AuthMagicLinkActionType.REGISTER], WhereTest.IN) + .get(); + } + + public async interruptAuth(req: Request, res: Response): Promise { + const pendingLink = await MagicLink.select() + .where('session_id', req.getSession().id) + .first(); + + if (pendingLink) { + if (await pendingLink.isValid()) { + res.redirect(Controller.route('magic_link_lobby', undefined, { + redirect_uri: req.getIntendedUrl() || pendingLink.original_url || undefined, + })); + return true; + } else { + await pendingLink.delete(); + } + } + + return false; + } + + public async attemptLogin(req: Request, res: Response, user: User): Promise { + const userEmail = user.mainEmail.getOrFail(); + if (!userEmail) throw new Error('No main email for user ' + user.id); + await this.auth(req, res, false, userEmail.getOrFail('email')); + } + + public async attemptRegister(req: Request, res: Response, identifier: string): Promise { + const userEmail = UserEmail.create({ + email: identifier, + main: true, + }); + await userEmail.validate(true); + await this.auth(req, res, true, identifier); + } + + private async auth(req: Request, res: Response, isRegistration: boolean, email: string): Promise { + const geo = geoip.lookup(req.ip); + const actionType = isRegistration ? AuthMagicLinkActionType.REGISTER : AuthMagicLinkActionType.LOGIN; + + if (isRegistration) { + const usernameValidator = new Validator(); + if (ModelFactory.get(User).hasComponent(UserNameComponent)) usernameValidator.defined(); + + await Validator.validate({ + email: new Validator().defined().unique(UserEmail, 'email'), + name: usernameValidator, + }, { + email: email, + name: req.body.name, + }); + } + + req.getSession().wantsSessionPersistence = !!req.body.persist_session || isRegistration; + + await MagicLinkController.sendMagicLink( + this.app, + req.getSession().id, + actionType, + Controller.route('auth', undefined, { + redirect_uri: req.getIntendedUrl() || undefined, + }), + email, + this.magicLinkMailTemplate, + { + type: actionType, + ip: req.ip, + geo: geo ? `${geo.city}, ${geo.country}` : 'Unknown location', + }, + { + username: req.body.name, + }, + ); + + res.redirect(Controller.route('magic_link_lobby', undefined, { + redirect_uri: req.getIntendedUrl(), + })); + } +} diff --git a/src/auth/magic_link/MagicLinkController.ts b/src/auth/magic_link/MagicLinkController.ts new file mode 100644 index 0000000..3df778c --- /dev/null +++ b/src/auth/magic_link/MagicLinkController.ts @@ -0,0 +1,258 @@ +import Controller from "../../Controller"; +import {Request, Response} from "express"; +import MagicLinkWebSocketListener from "./MagicLinkWebSocketListener"; +import {BadRequestError, NotFoundHttpError} from "../../HttpError"; +import Throttler from "../../Throttler"; +import Mail, {MailTemplate} from "../../mail/Mail"; +import MagicLink from "../models/MagicLink"; +import config from "config"; +import Application from "../../Application"; +import {ParsedUrlQueryInput} from "querystring"; +import NunjucksComponent from "../../components/NunjucksComponent"; +import User from "../models/User"; +import AuthComponent, {AuthMiddleware} from "../AuthComponent"; +import {AuthError, PendingApprovalAuthError, RegisterCallback} from "../AuthGuard"; +import UserEmail from "../models/UserEmail"; +import AuthMagicLinkActionType from "./AuthMagicLinkActionType"; +import {QueryVariable} from "../../db/MysqlConnectionManager"; +import UserNameComponent from "../models/UserNameComponent"; +import MagicLinkUserNameComponent from "../models/MagicLinkUserNameComponent"; +import {logger} from "../../Logger"; + +export default class MagicLinkController extends Controller { + public static async sendMagicLink( + app: Application, + sessionId: string, + actionType: string, + original_url: string, + email: string, + mailTemplate: MailTemplate, + data: ParsedUrlQueryInput, + magicLinkData: Record = {}, + ): Promise { + Throttler.throttle('magic_link', process.env.NODE_ENV === 'test' ? 10 : 2, MagicLink.validityPeriod(), + sessionId, 0, 0); + Throttler.throttle('magic_link', 1, MagicLink.validityPeriod(), + email, 0, 0); + + const link = MagicLink.create(Object.assign(magicLinkData, { + session_id: sessionId, + action_type: actionType, + original_url: original_url, + })); + + const token = await link.generateToken(email); + await link.save(); + + // Send email + await new Mail(app.as(NunjucksComponent).getEnvironment(), mailTemplate, Object.assign(data, { + link: `${config.get('public_url')}${Controller.route('magic_link', undefined, { + id: link.id, + token: token, + })}`, + })).send(email); + } + + public static async checkAndAuth(req: Request, res: Response, magicLink: MagicLink): Promise { + const session = req.getSession(); + if (magicLink.getOrFail('session_id') !== session.id) throw new BadOwnerMagicLink(); + if (!await magicLink.isAuthorized()) throw new UnauthorizedMagicLink(); + if (!await magicLink.isValid()) throw new InvalidMagicLink(); + + // Auth + try { + return await req.as(AuthMiddleware).getAuthGuard().authenticateOrRegister( + session, magicLink, !!session.wantsSessionPersistence, undefined, async (connection, user) => { + const userNameComponent = user.asOptional(UserNameComponent); + if (userNameComponent) userNameComponent.name = magicLink.as(MagicLinkUserNameComponent).username; + return []; + }, async (connection, user) => { + const callbacks: RegisterCallback[] = []; + + const userEmail = UserEmail.create({ + user_id: user.id, + email: magicLink.getOrFail('email'), + }); + await userEmail.save(connection, c => callbacks.push(c)); + user.main_email_id = userEmail.id; + await user.save(connection, c => callbacks.push(c)); + + return callbacks; + }); + } catch (e) { + if (e instanceof PendingApprovalAuthError) { + res.format({ + json: () => { + res.json({ + 'status': 'warning', + 'message': `Your account is pending review. You'll receive an email once you're approved.`, + }); + }, + html: () => { + req.flash('warning', `Your account is pending review. You'll receive an email once you're approved.`); + res.redirect('/'); + }, + }); + return null; + } else { + throw e; + } + } + } + + + protected readonly magicLinkWebsocketPath: string; + + public constructor(magicLinkWebsocketListener: MagicLinkWebSocketListener) { + super(); + this.magicLinkWebsocketPath = magicLinkWebsocketListener.path(); + } + + public getRoutesPrefix(): string { + return '/magic'; + } + + public routes(): void { + this.get('/lobby', this.getLobby, 'magic_link_lobby'); + this.get('/link', this.getMagicLink, 'magic_link'); + } + + protected async getLobby(req: Request, res: Response): Promise { + const link = await MagicLink.select() + .where('session_id', req.getSession().id) + .sortBy('authorized') + .where('used', 0) + .first(); + if (!link) { + throw new NotFoundHttpError('magic link', req.url); + } + + if (!await link.isValid()) { + req.flash('error', 'This magic link has expired. Please try again.'); + res.redirect(link.getOrFail('original_url')); + return; + } + + if (await link.isAuthorized()) { + link.use(); + await link.save(); + await this.performAction(link, req, res); + return; + } + + res.render('magic_link_lobby', { + email: link.getOrFail('email'), + type: link.getOrFail('action_type'), + validUntil: link.getExpirationDate().getTime(), + websocketUrl: config.get('public_websocket_url') + this.magicLinkWebsocketPath, + }); + } + + protected async getMagicLink(req: Request, res: Response): Promise { + const id = parseInt(req.query.id); + const token = req.query.token; + if (!id || !token) + throw new BadRequestError('Need parameters id, token.', 'Please try again.', req.originalUrl); + + let success = true; + let err; + const magicLink = await MagicLink.getById(id); + if (!magicLink) { + res.status(404); + err = `Couldn't find this magic link. Perhaps it has already expired.`; + success = false; + } else if (!await magicLink.isAuthorized()) { + err = await magicLink.verifyToken(token); + if (err === null) { + // Validation success, authenticate the user + magicLink.authorize(); + await magicLink.save(); + this.getApp().as>(MagicLinkWebSocketListener) + .refreshMagicLink(magicLink.getOrFail('session_id')); + } + } + + res.render('magic_link', { + magicLink: magicLink, + err: err, + success: success && err === null, + }); + } + + protected async performAction(magicLink: MagicLink, req: Request, res: Response): Promise { + switch (magicLink.getOrFail('action_type')) { + case AuthMagicLinkActionType.LOGIN: + case AuthMagicLinkActionType.REGISTER: { + await MagicLinkController.checkAndAuth(req, res, magicLink); + + const authGuard = this.getApp().as(AuthComponent).getAuthGuard(); + const proofs = await authGuard.getProofsForSession(req.getSession()); + const user = await proofs[0]?.getResource(); + + if (!res.headersSent && user) { + // Auth success + req.flash('success', `Authentication success. Welcome, ${user.name}!`); + res.redirect(req.getIntendedUrl() || Controller.route('home')); + } + break; + } + + case AuthMagicLinkActionType.ADD_EMAIL: { + const session = req.getSessionOptional(); + if (!session || magicLink.session_id !== session.id) throw new BadOwnerMagicLink(); + + await magicLink.delete(); + + const authGuard = this.getApp().as(AuthComponent).getAuthGuard(); + const proofs = await authGuard.getProofsForSession(session); + const user = await proofs[0]?.getResource(); + if (!user) return; + + const email = await magicLink.getOrFail('email'); + if (await UserEmail.select().with('user').where('email', email).first()) { + req.flash('error', 'An account already exists with this email address.' + + ' Please first remove it there before adding it here.'); + res.redirect(Controller.route('account')); + return; + } + + const userEmail = UserEmail.create({ + user_id: user.id, + email: email, + main: false, + }); + await userEmail.save(); + + if (!user.main_email_id) { + user.main_email_id = userEmail.id; + await user.save(); + } + + req.flash('success', `Email address ${userEmail.email} successfully added.`); + res.redirect(Controller.route('account')); + break; + } + default: + logger.warn('Unknown magic link action type ' + magicLink.action_type); + break; + } + } +} + +export class BadOwnerMagicLink extends AuthError { + public constructor() { + super(`This magic link doesn't belong to this session.`); + } +} + +export class UnauthorizedMagicLink extends AuthError { + public constructor() { + super(`This magic link is unauthorized.`); + } +} + +export class InvalidMagicLink extends AuthError { + public constructor() { + super(`This magic link is invalid.`); + } +} diff --git a/src/auth/magic_link/MagicLinkWebSocketListener.ts b/src/auth/magic_link/MagicLinkWebSocketListener.ts new file mode 100644 index 0000000..78746f0 --- /dev/null +++ b/src/auth/magic_link/MagicLinkWebSocketListener.ts @@ -0,0 +1,70 @@ +import WebSocket from "ws"; +import {IncomingMessage} from "http"; +import WebSocketListener from "../../WebSocketListener"; +import MagicLink from "../models/MagicLink"; +import Application from "../../Application"; +import {Session} from "express-session"; + +export default class MagicLinkWebSocketListener extends WebSocketListener { + private readonly connections: { [p: string]: (() => void)[] | undefined } = {}; + + public refreshMagicLink(sessionId: string): void { + const fs = this.connections[sessionId]; + if (fs) { + fs.forEach(f => f()); + } + } + + public async handle(socket: WebSocket, request: IncomingMessage, session: Session | null): Promise { + // Drop if requested without session + if (!session) { + socket.close(1002, 'Session is required for this request.'); + return; + } + + // Refuse any incoming data + socket.on('message', () => { + socket.close(1003); + }); + + // Get magic link + const magicLink = await MagicLink.select() + .where('session_id', session.id) + .sortBy('authorized') + .first(); + + // Refresh if immediately applicable + if (!magicLink || !await magicLink.isValid() || await magicLink.isAuthorized()) { + socket.send('refresh'); + socket.close(1000); + return; + } + + const validityTimeout = setTimeout(() => { + socket.send('refresh'); + socket.close(1000); + }, magicLink.getExpirationDate().getTime() - new Date().getTime()); + + const f = () => { + clearTimeout(validityTimeout); + socket.send('refresh'); + socket.close(1000); + }; + + socket.on('close', () => { + const connections = this.connections[session.id]; + if (connections) { + this.connections[session.id] = connections.filter(f => f !== f); + if (connections.length === 0) delete this.connections[session.id]; + } + }); + + let connections = this.connections[session.id]; + if (!connections) connections = this.connections[session.id] = []; + connections.push(f); + } + + public path(): string { + return '/magic-link'; + } +} diff --git a/src/auth/magic_link/MakeMagicLinksSessionNotUniqueMigration.ts b/src/auth/magic_link/MakeMagicLinksSessionNotUniqueMigration.ts new file mode 100644 index 0000000..ba6607e --- /dev/null +++ b/src/auth/magic_link/MakeMagicLinksSessionNotUniqueMigration.ts @@ -0,0 +1,12 @@ +import Migration from "../../db/Migration"; + +export default class MakeMagicLinksSessionNotUniqueMigration extends Migration { + public async install(): Promise { + await this.query(`ALTER TABLE magic_links + DROP INDEX IF EXISTS session_id`); + } + + public async rollback(): Promise { + await this.query('ALTER TABLE magic_links ADD CONSTRAINT UNIQUE (session_id)'); + } +} diff --git a/src/auth/migrations/AddApprovedFieldToUsersTableMigration.ts b/src/auth/migrations/AddApprovedFieldToUsersTableMigration.ts new file mode 100644 index 0000000..65d199b --- /dev/null +++ b/src/auth/migrations/AddApprovedFieldToUsersTableMigration.ts @@ -0,0 +1,18 @@ +import Migration from "../../db/Migration"; +import ModelFactory from "../../db/ModelFactory"; +import User from "../models/User"; +import UserApprovedComponent from "../models/UserApprovedComponent"; + +export default class AddApprovedFieldToUsersTableMigration extends Migration { + public async install(): Promise { + await this.query('ALTER TABLE users ADD COLUMN approved BOOLEAN NOT NULL DEFAULT 0'); + } + + public async rollback(): Promise { + await this.query('ALTER TABLE users DROP COLUMN approved'); + } + + public registerModels(): void { + ModelFactory.get(User).addComponent(UserApprovedComponent); + } +} diff --git a/src/auth/migrations/AddNameToUsersMigration.ts b/src/auth/migrations/AddNameToUsersMigration.ts new file mode 100644 index 0000000..0c3bfb0 --- /dev/null +++ b/src/auth/migrations/AddNameToUsersMigration.ts @@ -0,0 +1,25 @@ +import Migration from "../../db/Migration"; +import ModelFactory from "../../db/ModelFactory"; +import User from "../models/User"; +import UserNameComponent from "../models/UserNameComponent"; +import MagicLink from "../models/MagicLink"; +import MagicLinkUserNameComponent from "../models/MagicLinkUserNameComponent"; + +export default class AddNameToUsersMigration extends Migration { + public async install(): Promise { + await this.query(`ALTER TABLE users + ADD COLUMN name VARCHAR(64) UNIQUE NOT NULL`); + await this.query(`ALTER TABLE magic_links + ADD COLUMN username VARCHAR(64) DEFAULT NULL`); + } + + public async rollback(): Promise { + await this.query('ALTER TABLE users DROP COLUMN name'); + await this.query('ALTER TABLE magic_links DROP COLUMN username'); + } + + public registerModels(): void { + ModelFactory.get(User).addComponent(UserNameComponent); + ModelFactory.get(MagicLink).addComponent(MagicLinkUserNameComponent); + } +} diff --git a/src/auth/migrations/CreateUsersAndUserEmailsTableMigration.ts b/src/auth/migrations/CreateUsersAndUserEmailsTableMigration.ts new file mode 100644 index 0000000..5aaf814 --- /dev/null +++ b/src/auth/migrations/CreateUsersAndUserEmailsTableMigration.ts @@ -0,0 +1,39 @@ +import Migration from "../../db/Migration"; +import ModelFactory from "../../db/ModelFactory"; +import User from "../models/User"; +import UserEmail from "../models/UserEmail"; + +export default class CreateUsersAndUserEmailsTableMigration extends Migration { + public async install(): Promise { + await this.query(`CREATE TABLE users + ( + id INT NOT NULL AUTO_INCREMENT, + main_email_id INT, + is_admin BOOLEAN NOT NULL DEFAULT false, + created_at DATETIME NOT NULL DEFAULT NOW(), + updated_at DATETIME NOT NULL DEFAULT NOW(), + PRIMARY KEY (id) + )`); + await this.query(`CREATE TABLE user_emails + ( + id INT NOT NULL AUTO_INCREMENT, + user_id INT NOT NULL, + email VARCHAR(254) UNIQUE NOT NULL, + created_at DATETIME NOT NULL DEFAULT NOW(), + PRIMARY KEY (id), + FOREIGN KEY user_fk (user_id) REFERENCES users (id) ON DELETE CASCADE + )`); + await this.query(`ALTER TABLE users + ADD FOREIGN KEY main_user_email_fk (main_email_id) REFERENCES user_emails (id) ON DELETE SET NULL`); + } + + public async rollback(): Promise { + await this.query('DROP TABLE user_emails'); + await this.query('DROP TABLE users'); + } + + public registerModels(): void { + ModelFactory.register(User); + ModelFactory.register(UserEmail); + } +} diff --git a/src/auth/migrations/DropNameFromUsers.ts b/src/auth/migrations/DropNameFromUsers.ts new file mode 100644 index 0000000..1c7352a --- /dev/null +++ b/src/auth/migrations/DropNameFromUsers.ts @@ -0,0 +1,14 @@ +import Migration from "../../db/Migration"; + +/** + * @deprecated - TODO may be remove at next major version >= 0.24, replace with DummyMigration. + */ +export default class DropNameFromUsers extends Migration { + public async install(): Promise { + await this.query('ALTER TABLE users DROP COLUMN name'); + } + + public async rollback(): Promise { + await this.query('ALTER TABLE users ADD COLUMN name VARCHAR(64)'); + } +} diff --git a/src/auth/migrations/FixUserMainEmailRelation.ts b/src/auth/migrations/FixUserMainEmailRelation.ts new file mode 100644 index 0000000..db32337 --- /dev/null +++ b/src/auth/migrations/FixUserMainEmailRelation.ts @@ -0,0 +1,27 @@ +import Migration from "../../db/Migration"; + +/** + * @deprecated - TODO may be remove at next major version >= 0.24, replace with DummyMigration. + */ +export default class FixUserMainEmailRelation extends Migration { + public async install(): Promise { + await this.query(`ALTER TABLE users + ADD COLUMN main_email_id INT, + ADD FOREIGN KEY main_user_email_fk (main_email_id) REFERENCES user_emails (id)`); + await this.query(`UPDATE users u LEFT JOIN user_emails ue ON u.id = ue.user_id + SET u.main_email_id=ue.id + WHERE ue.main = true`); + await this.query(`ALTER TABLE user_emails + DROP COLUMN main`); + } + + public async rollback(): Promise { + await this.query(`ALTER TABLE user_emails + ADD COLUMN main BOOLEAN DEFAULT false`); + await this.query(`UPDATE user_emails ue LEFT JOIN users u ON ue.id = u.main_email_id + SET ue.main = true`); + await this.query(`ALTER TABLE users + DROP FOREIGN KEY main_user_email_fk, + DROP COLUMN main_email_id`); + } +} diff --git a/src/auth/models/MagicLink.ts b/src/auth/models/MagicLink.ts new file mode 100644 index 0000000..7af67f4 --- /dev/null +++ b/src/auth/models/MagicLink.ts @@ -0,0 +1,106 @@ +import crypto from "crypto"; +import config from "config"; +import Model from "../../db/Model"; +import AuthProof from "../AuthProof"; +import User from "./User"; +import argon2 from "argon2"; +import UserEmail from "./UserEmail"; +import {EMAIL_REGEX} from "../../db/Validator"; + +export default class MagicLink extends Model implements AuthProof { + public static validityPeriod(): number { + return config.get('magic_link.validity_period') * 1000; + } + + public readonly id?: number = undefined; + public readonly session_id?: string = undefined; + private email?: string = undefined; + private token?: string = undefined; + public readonly action_type?: string = undefined; + public readonly original_url?: string = undefined; + private generated_at?: Date = undefined; + private authorized: boolean = false; + private used: boolean = false; + + protected init(): void { + this.setValidation('session_id').defined().length(32); + this.setValidation('email').defined().regexp(EMAIL_REGEX); + this.setValidation('token').defined().length(96); + this.setValidation('action_type').defined().maxLength(64); + this.setValidation('original_url').defined().maxLength(1745); + this.setValidation('authorized').defined(); + this.setValidation('used').defined(); + } + + public async getResource(): Promise { + const email = await UserEmail.select() + .with('user') + .where('email', await this.getOrFail('email')) + .first(); + return email ? await email.user.get() : null; + } + + public async revoke(): Promise { + await this.delete(); + } + + public async isValid(): Promise { + return await this.isAuthorized() || + new Date().getTime() < this.getExpirationDate().getTime(); + } + + public async isAuthorized(): Promise { + return this.authorized; + } + + public authorize(): void { + this.authorized = true; + } + + public isUsed(): boolean { + return this.used; + } + + public use(): void { + this.used = true; + } + + public async generateToken(email: string): Promise { + const rawToken = crypto.randomBytes(48).toString('base64'); // Raw token length = 64 + this.email = email; + this.generated_at = new Date(); + this.token = await argon2.hash(rawToken, { + timeCost: 10, + memoryCost: 4096, + parallelism: 4, + hashLength: 32, + }); + return rawToken; + } + + /** + * @returns {@code null} if the token is valid, an error {@code string} otherwise. + */ + public async verifyToken(tokenGuess: string): Promise { + // There is no token + if (this.token === undefined || this.generated_at === undefined) + return 'This token was not generated.'; + + // Token has expired + if (new Date().getTime() - this.generated_at.getTime() > MagicLink.validityPeriod()) + return 'This token has expired.'; + + // Token is invalid + if (!await argon2.verify(this.token, tokenGuess)) + return 'This token is invalid.'; + + return null; + } + + + public getExpirationDate(): Date { + if (!this.generated_at) return new Date(); + + return new Date(this.generated_at.getTime() + MagicLink.validityPeriod()); + } +} diff --git a/src/auth/models/MagicLinkUserNameComponent.ts b/src/auth/models/MagicLinkUserNameComponent.ts new file mode 100644 index 0000000..f4fb2ca --- /dev/null +++ b/src/auth/models/MagicLinkUserNameComponent.ts @@ -0,0 +1,12 @@ +import ModelComponent from "../../db/ModelComponent"; +import MagicLink from "./MagicLink"; +import {USERNAME_REGEXP} from "./UserNameComponent"; +import User from "./User"; + +export default class MagicLinkUserNameComponent extends ModelComponent { + public readonly username?: string = undefined; + + protected init(): void { + this.setValidation('username').acceptUndefined().between(3, 64).regexp(USERNAME_REGEXP).unique(User, 'name'); + } +} diff --git a/src/auth/models/User.ts b/src/auth/models/User.ts new file mode 100644 index 0000000..a08dc69 --- /dev/null +++ b/src/auth/models/User.ts @@ -0,0 +1,53 @@ +import Model from "../../db/Model"; +import MysqlConnectionManager from "../../db/MysqlConnectionManager"; +import AddApprovedFieldToUsersTableMigration from "../migrations/AddApprovedFieldToUsersTableMigration"; +import config from "config"; +import {ManyModelRelation} from "../../db/ModelRelation"; +import UserEmail from "./UserEmail"; +import UserApprovedComponent from "./UserApprovedComponent"; +import UserNameComponent from "./UserNameComponent"; + +export default class User extends Model { + public static isApprovalMode(): boolean { + return config.get('approval_mode') && + MysqlConnectionManager.hasMigration(AddApprovedFieldToUsersTableMigration); + } + + public readonly id?: number = undefined; + public main_email_id?: number = undefined; + public is_admin: boolean = false; + public created_at?: Date = undefined; + public updated_at?: Date = undefined; + + public readonly emails = new ManyModelRelation(this, UserEmail, { + localKey: 'id', + foreignKey: 'user_id', + }); + + public readonly mainEmail = this.emails.cloneReduceToOne().constraint(q => q.where('id', this.main_email_id)); + + protected init(): void { + this.setValidation('name').acceptUndefined().between(3, 64); + this.setValidation('main_email_id').acceptUndefined().exists(UserEmail, 'id'); + if (User.isApprovalMode()) { + this.setValidation('approved').defined(); + } + this.setValidation('is_admin').defined(); + } + + public isApproved(): boolean { + return !User.isApprovalMode() || this.as(UserApprovedComponent).approved; + } + + protected getPersonalInfoFields(): { name: string, value: string }[] { + const fields: { name: string, value: string }[] = []; + const nameComponent = this.asOptional(UserNameComponent); + if (nameComponent && nameComponent.name) { + fields.push({ + name: 'Name', + value: nameComponent.name, + }); + } + return fields; + } +} diff --git a/src/auth/models/UserApprovedComponent.ts b/src/auth/models/UserApprovedComponent.ts new file mode 100644 index 0000000..648dfa9 --- /dev/null +++ b/src/auth/models/UserApprovedComponent.ts @@ -0,0 +1,6 @@ +import ModelComponent from "../../db/ModelComponent"; +import User from "./User"; + +export default class UserApprovedComponent extends ModelComponent { + public approved: boolean = false; +} diff --git a/src/auth/models/UserEmail.ts b/src/auth/models/UserEmail.ts new file mode 100644 index 0000000..e3d58e8 --- /dev/null +++ b/src/auth/models/UserEmail.ts @@ -0,0 +1,22 @@ +import User from "./User"; +import Model from "../../db/Model"; +import {OneModelRelation} from "../../db/ModelRelation"; +import {EMAIL_REGEX} from "../../db/Validator"; + +export default class UserEmail extends Model { + public readonly id?: number = undefined; + public user_id?: number = undefined; + public readonly email?: string = undefined; + public created_at?: Date = undefined; + + public readonly user = new OneModelRelation(this, User, { + localKey: 'user_id', + foreignKey: 'id', + }); + + protected init(): void { + this.setValidation('user_id').acceptUndefined().exists(User, 'id'); + this.setValidation('email').defined().regexp(EMAIL_REGEX).unique(this); + this.setValidation('main').defined(); + } +} diff --git a/src/auth/models/UserNameComponent.ts b/src/auth/models/UserNameComponent.ts new file mode 100644 index 0000000..930b794 --- /dev/null +++ b/src/auth/models/UserNameComponent.ts @@ -0,0 +1,12 @@ +import ModelComponent from "../../db/ModelComponent"; +import User from "../models/User"; + +export const USERNAME_REGEXP = /^[0-9a-z_-]+$/; + +export default class UserNameComponent extends ModelComponent { + public name?: string = undefined; + + public init(): void { + this.setValidation('name').defined().between(3, 64).regexp(USERNAME_REGEXP).unique(this._model); + } +} diff --git a/src/auth/password/AddPasswordToUsersMigration.ts b/src/auth/password/AddPasswordToUsersMigration.ts new file mode 100644 index 0000000..520b4df --- /dev/null +++ b/src/auth/password/AddPasswordToUsersMigration.ts @@ -0,0 +1,20 @@ +import Migration from "../../db/Migration"; +import ModelFactory from "../../db/ModelFactory"; +import User from "../models/User"; +import UserPasswordComponent from "./UserPasswordComponent"; + +export default class AddPasswordToUsersMigration extends Migration { + public async install(): Promise { + await this.query(`ALTER TABLE users + ADD COLUMN password VARCHAR(128) DEFAULT NULL`); + } + + public async rollback(): Promise { + await this.query(`ALTER TABLE users + DROP COLUMN password`); + } + + public registerModels(): void { + ModelFactory.get(User).addComponent(UserPasswordComponent); + } +} diff --git a/src/auth/password/PasswordAuthMethod.ts b/src/auth/password/PasswordAuthMethod.ts new file mode 100644 index 0000000..27bd85e --- /dev/null +++ b/src/auth/password/PasswordAuthMethod.ts @@ -0,0 +1,139 @@ +import AuthMethod from "../AuthMethod"; +import PasswordAuthProof from "./PasswordAuthProof"; +import User from "../models/User"; +import {Request, Response} from "express"; +import UserEmail from "../models/UserEmail"; +import AuthComponent from "../AuthComponent"; +import Application from "../../Application"; +import Throttler from "../../Throttler"; +import {AuthError, PendingApprovalAuthError, RegisterCallback} from "../AuthGuard"; +import Validator, {InvalidFormatValidationError} from "../../db/Validator"; +import Controller from "../../Controller"; +import UserPasswordComponent from "./UserPasswordComponent"; +import UserNameComponent, {USERNAME_REGEXP} from "../models/UserNameComponent"; +import ModelFactory from "../../db/ModelFactory"; +import {ServerError} from "../../HttpError"; +import {Session} from "express-session"; + +export default class PasswordAuthMethod implements AuthMethod { + public constructor( + protected readonly app: Application, + ) { + } + + public getName(): string { + return 'password'; + } + + public getWeightForRequest(req: Request): number { + return !req.body.identifier || !req.body.password || req.body.password.length === 0 ? + 0 : + 2; + } + + public async findUserByIdentifier(identifier: string): Promise { + const query = UserEmail.select() + .with('user') + .where('email', identifier); + + const user = (await query + .first())?.user.getOrFail(); + if (user) return user; + + if (ModelFactory.get(User).hasComponent(UserNameComponent)) { + return await User.select().where('name', identifier).first(); + } + + return null; + } + + public async getProofsForSession(session: Session): Promise { + const proof = PasswordAuthProof.getProofForSession(session); + return proof ? [proof] : []; + } + + public async attemptLogin(req: Request, res: Response, user: User): Promise { + const passwordAuthProof = PasswordAuthProof.createProofForLogin(req.getSession()); + passwordAuthProof.setResource(user); + + await passwordAuthProof.authorize(req.body.password); + try { + await this.app.as(AuthComponent).getAuthGuard().authenticateOrRegister( + req.getSession(), + passwordAuthProof, + !!req.body.persist_session, + ); + } catch (e) { + if (e instanceof AuthError) { + Throttler.throttle('login_failed_attempts_user', 3, 3 * 60 * 1000, // 3min + user.getOrFail('name'), 1000, 60 * 1000); // 1min + Throttler.throttle('login_failed_attempts_ip', 50, 60 * 1000, // 1min + req.ip, 1000, 3600 * 1000); // 1h + + if (e instanceof PendingApprovalAuthError) { + req.flash('error', 'Your account is still being reviewed.'); + res.redirect(Controller.route('auth')); + return; + } else { + const err = new InvalidFormatValidationError('Invalid password.'); + err.thingName = 'password'; + throw err; + } + } else { + throw e; + } + } + + req.flash('success', `Welcome, ${user.name}.`); + res.redirect(req.getIntendedUrl() || Controller.route('home')); + } + + public async attemptRegister(req: Request, res: Response, identifier: string): Promise { + if (!ModelFactory.get(User).hasComponent(UserNameComponent)) + throw new ServerError('Cannot register with password without UserNameComponent.'); + + Throttler.throttle('register_password', 10, 30000, req.ip); + + req.body.identifier = identifier; + + await Validator.validate({ + identifier: new Validator().defined().between(3, 64).regexp(USERNAME_REGEXP).unique(User, 'name'), + password: new Validator().defined().minLength(UserPasswordComponent.PASSWORD_MIN_LENGTH), + password_confirmation: new Validator().defined().sameAs('password', req.body.password), + terms: new Validator().defined(), + }, req.body); + + const passwordAuthProof = PasswordAuthProof.createAuthorizedProofForRegistration(req.getSession()); + try { + await this.app.as(AuthComponent).getAuthGuard().authenticateOrRegister(req.getSession(), passwordAuthProof, + true, undefined, async (connection, user) => { + const callbacks: RegisterCallback[] = []; + + // Password + await user.as(UserPasswordComponent).setPassword(req.body.password); + + // Username + user.as(UserNameComponent).name = req.body.identifier; + + return callbacks; + }, async (connection, user) => { + passwordAuthProof.setResource(user); + return []; + }); + } catch (e) { + if (e instanceof PendingApprovalAuthError) { + req.flash('info', `Your account was successfully created and is pending review from an administrator.`); + res.redirect(Controller.route('auth')); + return; + } else { + throw e; + } + } + + const user = await passwordAuthProof.getResource(); + + req.flash('success', `Your account was successfully created! Welcome, ${user?.as(UserNameComponent).name}.`); + res.redirect(req.getIntendedUrl() || Controller.route('home')); + } + +} diff --git a/src/auth/password/PasswordAuthProof.ts b/src/auth/password/PasswordAuthProof.ts new file mode 100644 index 0000000..dca436f --- /dev/null +++ b/src/auth/password/PasswordAuthProof.ts @@ -0,0 +1,89 @@ +import AuthProof from "../AuthProof"; +import User from "../models/User"; +import UserPasswordComponent from "./UserPasswordComponent"; +import {Session, SessionData} from "express-session"; + + +export default class PasswordAuthProof implements AuthProof { + public static getProofForSession(session: Session & Partial): PasswordAuthProof | null { + return session.authPasswordProof ? new PasswordAuthProof(session) : null; + } + + public static createAuthorizedProofForRegistration(session: Session): PasswordAuthProof { + const proofForSession = new PasswordAuthProof(session); + proofForSession.authorized = true; + proofForSession.forRegistration = true; + proofForSession.save(); + return proofForSession; + } + + public static createProofForLogin(session: Session & Partial): PasswordAuthProof { + return new PasswordAuthProof(session); + } + + private readonly session: Session & Partial; + private authorized: boolean; + private forRegistration: boolean = false; + private userId: number | null; + private userPassword: UserPasswordComponent | null = null; + + private constructor(session: Session & Partial) { + this.session = session; + this.authorized = session.authPasswordProof?.authorized || false; + this.forRegistration = session.authPasswordProof?.forRegistration || false; + this.userId = session.authPasswordProof?.userId || null; + } + + public async getResource(): Promise { + if (typeof this.userId !== 'number') return null; + return await User.getById(this.userId); + } + + public setResource(user: User): void { + this.userId = user.getOrFail('id'); + this.save(); + } + + public async isAuthorized(): Promise { + return this.authorized; + } + + public async isValid(): Promise { + return (this.forRegistration || Boolean(await this.getResource())) && + await this.isAuthorized(); + } + + public async revoke(): Promise { + this.session.authPasswordProof = undefined; + } + + private async getUserPassword(): Promise { + if (!this.userPassword) { + this.userPassword = (await User.getById(this.userId))?.as(UserPasswordComponent) || null; + } + return this.userPassword; + } + + public async authorize(passwordGuess: string): Promise { + const password = await this.getUserPassword(); + if (!password || !await password.verifyPassword(passwordGuess)) return false; + + this.authorized = true; + this.save(); + return true; + } + + private save() { + this.session.authPasswordProof = { + authorized: this.authorized, + forRegistration: this.forRegistration, + userId: this.userId, + }; + } +} + +export type PasswordAuthProofSessionData = { + authorized: boolean, + forRegistration: boolean, + userId: number | null, +}; diff --git a/src/auth/password/UserPasswordComponent.ts b/src/auth/password/UserPasswordComponent.ts new file mode 100644 index 0000000..e1c25a7 --- /dev/null +++ b/src/auth/password/UserPasswordComponent.ts @@ -0,0 +1,39 @@ +import argon2, {argon2id} from "argon2"; +import ModelComponent from "../../db/ModelComponent"; +import User from "../models/User"; +import Validator from "../../db/Validator"; + +export default class UserPasswordComponent extends ModelComponent { + public static readonly PASSWORD_MIN_LENGTH = 12; + + private password?: string = undefined; + + public init(): void { + this.setValidation('password').acceptUndefined().maxLength(128); + } + + public async setPassword(rawPassword: string, fieldName: string = 'password'): Promise { + await new Validator() + .defined() + .minLength(UserPasswordComponent.PASSWORD_MIN_LENGTH) + .maxLength(512) + .execute(fieldName, rawPassword, true); + this.password = await argon2.hash(rawPassword, { + timeCost: 10, + memoryCost: 65536, + parallelism: 4, + type: argon2id, + hashLength: 32, + }); + } + + public async verifyPassword(passwordGuess: string): Promise { + if (!this.password || !passwordGuess) return false; + + return await argon2.verify(this.password, passwordGuess); + } + + public hasPassword(): boolean { + return typeof this.password === 'string'; + } +} diff --git a/src/components/AutoUpdateComponent.ts b/src/components/AutoUpdateComponent.ts new file mode 100644 index 0000000..15cea80 --- /dev/null +++ b/src/components/AutoUpdateComponent.ts @@ -0,0 +1,55 @@ +import {Router} from "express"; +import config from "config"; +import * as child_process from "child_process"; +import ApplicationComponent from "../ApplicationComponent"; +import {ForbiddenHttpError} from "../HttpError"; +import {logger} from "../Logger"; + +export default class AutoUpdateComponent extends ApplicationComponent { + private static async runCommand(command: string): Promise { + logger.info(`> ${command}`); + logger.info(child_process.execSync(command).toString()); + } + + public async checkSecuritySettings(): Promise { + this.checkSecurityConfigField('gitlab_webhook_token'); + } + + public async init(router: Router): Promise { + router.post('/update/push.json', (req, res) => { + const token = req.header('X-Gitlab-Token'); + if (!token || token !== config.get('gitlab_webhook_token')) + throw new ForbiddenHttpError('Invalid token', req.url); + + this.update(req.body).catch(logger.error); + + res.json({ + 'status': 'ok', + }); + }); + } + + private async update(params: { [p: string]: unknown }) { + logger.info('Update params:', params); + + try { + logger.info('Starting auto update...'); + + // Fetch + await AutoUpdateComponent.runCommand(`git pull`); + + // Install new dependencies + await AutoUpdateComponent.runCommand(`yarn install --production=false`); + + // Process assets + await AutoUpdateComponent.runCommand(`yarn dist`); + + // Stop app + await this.getApp().stop(); + + logger.info('Success!'); + } catch (e) { + logger.error(e, 'An error occurred while running the auto update.'); + } + } +} diff --git a/src/components/CsrfProtectionComponent.ts b/src/components/CsrfProtectionComponent.ts index 5db4074..614f7fc 100644 --- a/src/components/CsrfProtectionComponent.ts +++ b/src/components/CsrfProtectionComponent.ts @@ -1,54 +1,70 @@ import ApplicationComponent from "../ApplicationComponent"; -import {Express, Router} from "express"; +import {Request, Router} from "express"; import crypto from "crypto"; import {BadRequestError} from "../HttpError"; +import {AuthMiddleware} from "../auth/AuthComponent"; +import {Session, SessionData} from "express-session"; -export default class CsrfProtectionComponent extends ApplicationComponent { - public async start(app: Express, router: Router): Promise { - router.use((req, res, next) => { - if (!req.session) { - throw new Error('Session is unavailable.'); +export default class CsrfProtectionComponent extends ApplicationComponent { + private static readonly excluders: ((req: Request) => boolean)[] = []; + + public static getCsrfToken(session: Session & Partial): string { + if (typeof session.csrf !== 'string') { + session.csrf = crypto.randomBytes(64).toString('base64'); + } + return session.csrf; + } + + public static addExcluder(excluder: (req: Request) => boolean): void { + this.excluders.push(excluder); + } + + public async handle(router: Router): Promise { + router.use(async (req, res, next) => { + for (const excluder of CsrfProtectionComponent.excluders) { + if (excluder(req)) return next(); } - res.locals.getCSRFToken = () => { - if (typeof req.session!.csrf !== 'string') { - req.session!.csrf = crypto.randomBytes(64).toString('base64'); - } - return req.session!.csrf; + const session = req.getSession(); + res.locals.getCsrfToken = () => { + return CsrfProtectionComponent.getCsrfToken(session); }; if (!['GET', 'HEAD', 'OPTIONS'].find(s => s === req.method)) { - if (req.session.csrf === undefined) { - throw new InvalidCsrfTokenError(req.baseUrl, `You weren't assigned any CSRF token.`); - } else if (req.body.csrf === undefined) { - throw new InvalidCsrfTokenError(req.baseUrl, `You didn't provide any CSRF token.`); - } else if (req.session.csrf !== req.body.csrf) { - throw new InvalidCsrfTokenError(req.baseUrl, `Tokens don't match.`); + try { + if ((await req.as(AuthMiddleware).getAuthGuard().getProofsForRequest(req)).length === 0) { + if (session.csrf === undefined) { + return next(new InvalidCsrfTokenError(req.baseUrl, `You weren't assigned any CSRF token.`)); + } else if (req.body.csrf === undefined) { + return next(new InvalidCsrfTokenError(req.baseUrl, `You didn't provide any CSRF token.`)); + } else if (session.csrf !== req.body.csrf) { + return next(new InvalidCsrfTokenError(req.baseUrl, `Tokens don't match.`)); + } + } + } catch (e) { + return next(e); } } next(); }); } - - public async stop(): Promise { - } } class InvalidCsrfTokenError extends BadRequestError { - constructor(url: string, details: string, cause?: Error) { + public constructor(url: string, details: string, cause?: Error) { super( `Invalid CSRF token`, `${details} We can't process this request. Please try again.`, url, - cause + cause, ); } - get name(): string { + public get name(): string { return 'Invalid CSRF Token'; } - get errorCode(): number { + public get errorCode(): number { return 401; } } diff --git a/src/components/ExpressAppComponent.ts b/src/components/ExpressAppComponent.ts index ce4a57b..5ab489a 100644 --- a/src/components/ExpressAppComponent.ts +++ b/src/components/ExpressAppComponent.ts @@ -1,35 +1,60 @@ import ApplicationComponent from "../ApplicationComponent"; import express, {Express, Router} from "express"; -import Logger from "../Logger"; +import {logger, preventContextCorruptionMiddleware} from "../Logger"; import {Server} from "http"; +import compression from "compression"; +import Middleware from "../Middleware"; +import {Type} from "../Utils"; -export default class ExpressAppComponent extends ApplicationComponent { +export default class ExpressAppComponent extends ApplicationComponent { + private readonly addr: string; private readonly port: number; private server?: Server; + private expressApp?: Express; - constructor(port: number) { + public constructor(addr: string, port: number) { super(); + this.addr = addr; this.port = port; } - public async start(app: Express, router: Router): Promise { - this.server = app.listen(this.port, 'localhost', () => { - Logger.info(`Web server running on localhost:${this.port}.`); + public async start(app: Express): Promise { + this.server = app.listen(this.port, this.addr, () => { + logger.info(`Web server running on ${this.addr}:${this.port}.`); }); - router.use(express.json()); - router.use(express.urlencoded()); + // Proxy + app.set('trust proxy', 'loopback'); + + this.expressApp = app; + } + + public async init(router: Router): Promise { + router.use(preventContextCorruptionMiddleware(express.json({ + type: req => req.headers['content-type']?.match(/^application\/(.+\+)?json$/), + }))); + router.use(preventContextCorruptionMiddleware(express.urlencoded({ + extended: true, + }))); + + // gzip + router.use(compression()); router.use((req, res, next) => { - req.models = {}; - req.modelCollections = {}; + req.middlewares = []; + req.as = (type: Type): M => { + const middleware = req.middlewares.find(m => m.constructor === type); + if (!middleware) throw new Error('Middleware ' + type.name + ' not present in this request.'); + return middleware as M; + }; next(); }); } public async stop(): Promise { - if (this.server) { - await this.close('Webserver', this.server, this.server.close); + const server = this.server; + if (server) { + await this.close('Webserver', callback => server.close(callback)); } } @@ -37,4 +62,9 @@ export default class ExpressAppComponent extends ApplicationComponent { if (!this.server) throw 'Server was not initialized.'; return this.server; } -} \ No newline at end of file + + public getExpressApp(): Express { + if (!this.expressApp) throw new Error('Express app not initialized.'); + return this.expressApp; + } +} diff --git a/src/components/FormHelperComponent.ts b/src/components/FormHelperComponent.ts index 607e223..93f0693 100644 --- a/src/components/FormHelperComponent.ts +++ b/src/components/FormHelperComponent.ts @@ -1,16 +1,10 @@ import ApplicationComponent from "../ApplicationComponent"; -import {Express, Router} from "express"; +import {Router} from "express"; -export default class FormHelperComponent extends ApplicationComponent { - public async start(app: Express, router: Router): Promise { +export default class FormHelperComponent extends ApplicationComponent { + public async init(router: Router): Promise { router.use((req, res, next) => { - if (!req.session) { - throw new Error('Session is unavailable.'); - } - - res.locals.query = req.query; - - let _validation: any = null; + let _validation: unknown | null; res.locals.validation = () => { if (!_validation) { const v = req.flash('validation'); @@ -18,9 +12,9 @@ export default class FormHelperComponent extends ApplicationComponent { } return _validation; - } + }; - let _previousFormData: any = null; + let _previousFormData: unknown | null = null; res.locals.previousFormData = () => { if (!_previousFormData) { const v = req.flash('previousFormData'); @@ -41,8 +35,4 @@ export default class FormHelperComponent extends ApplicationComponent { next(); }); } - - public async stop(): Promise { - } - -} \ No newline at end of file +} diff --git a/src/components/LogRequestsComponent.ts b/src/components/LogRequestsComponent.ts index a77c4f2..6be5560 100644 --- a/src/components/LogRequestsComponent.ts +++ b/src/components/LogRequestsComponent.ts @@ -1,21 +1,87 @@ import ApplicationComponent from "../ApplicationComponent"; import onFinished from "on-finished"; -import Logger from "../Logger"; -import {Express, Router} from "express"; +import {logger} from "../Logger"; +import {Request, Response, Router} from "express"; +import {HttpError} from "../HttpError"; -export default class LogRequestsComponent extends ApplicationComponent { - public async start(app: Express, router: Router): Promise { +export default class LogRequestsComponent extends ApplicationComponent { + private static fullRequests: boolean = false; + + public static logFullHttpRequests(): void { + this.fullRequests = true; + logger.info('Http requests will be logged with more details.'); + } + + public static logRequest( + req: Request, + res: Response, + err?: unknown, + additionalStr: string = '', + silent: boolean = false, + ): string | undefined { + if (LogRequestsComponent.fullRequests) { + const requestObj = JSON.stringify({ + ip: req.ip, + host: req.hostname, + method: req.method, + url: req.originalUrl, + headers: req.headers, + query: req.query, + params: req.params, + body: req.body, + files: req.files, + cookies: req.cookies, + sessionId: req.sessionID, + result: { + code: res.statusCode, + }, + }, null, 4); + if (err) { + if (err instanceof Error) { + return logger.error(err, requestObj, err).requestId; + } else { + return logger.error(new Error(String(err)), requestObj).requestId; + } + } else { + logger.info(requestObj); + } + } else { + let codeDescription = ''; + if (res.statusCode === 301) { + codeDescription = 'Permanent redirect to ' + res.getHeader('location'); + } else if (res.statusCode === 302) { + codeDescription = 'Temporary redirect to ' + res.getHeader('location'); + } + + let logStr = `${req.ip} < ${req.method} ${req.originalUrl} - ${res.statusCode} ${codeDescription}`; + if (err) { + if (err instanceof Error) { + if (silent) { + if (err instanceof HttpError) logStr += ` ${err.errorCode}`; + logStr += ` ${err.name}`; + return logger.info(err.name, logStr).requestId; + } else { + return logger.error(err, logStr, additionalStr, err).requestId; + } + } else { + return logger.error(new Error(String(err)), logStr).requestId; + } + } else { + logger.info(logStr); + } + } + + return ''; + } + + public async init(router: Router): Promise { router.use((req, res, next) => { onFinished(res, (err) => { if (!err) { - Logger.info(`${req.method} ${req.originalUrl} - ${res.statusCode}`); + LogRequestsComponent.logRequest(req, res); } }); next(); }); } - - public async stop(): Promise { - } - -} \ No newline at end of file +} diff --git a/src/components/MailComponent.ts b/src/components/MailComponent.ts index e204b14..73c3e93 100644 --- a/src/components/MailComponent.ts +++ b/src/components/MailComponent.ts @@ -1,9 +1,21 @@ import ApplicationComponent from "../ApplicationComponent"; -import {Express, Router} from "express"; -import Mail from "../Mail"; +import {Express} from "express"; +import Mail from "../mail/Mail"; +import config from "config"; +import SecurityError from "../SecurityError"; -export default class MailComponent extends ApplicationComponent { - public async start(app: Express, router: Router): Promise { +export default class MailComponent extends ApplicationComponent { + + public async checkSecuritySettings(): Promise { + if (!config.get('mail.secure')) { + throw new SecurityError('Cannot set mail.secure (starttls) to false'); + } + if (config.get('mail.allow_invalid_tls')) { + throw new SecurityError('Cannot set mail.allow_invalid_tls (ignore tls failure) to true'); + } + } + + public async start(_app: Express): Promise { await this.prepare('Mail connection', () => Mail.prepare()); } @@ -11,4 +23,4 @@ export default class MailComponent extends ApplicationComponent { Mail.end(); } -} \ No newline at end of file +} diff --git a/src/components/MaintenanceComponent.ts b/src/components/MaintenanceComponent.ts index 76a18d7..ebfd8a3 100644 --- a/src/components/MaintenanceComponent.ts +++ b/src/components/MaintenanceComponent.ts @@ -1,19 +1,20 @@ import ApplicationComponent from "../ApplicationComponent"; -import {Express, NextFunction, Request, Response, Router} from "express"; +import {NextFunction, Request, Response, Router} from "express"; import {ServiceUnavailableHttpError} from "../HttpError"; import Application from "../Application"; +import config from "config"; -export default class MaintenanceComponent extends ApplicationComponent { +export default class MaintenanceComponent extends ApplicationComponent { private readonly application: Application; private readonly canServe: () => boolean; - constructor(application: Application, canServe: () => boolean) { + public constructor(application: Application, canServe: () => boolean) { super(); this.application = application; this.canServe = canServe; } - public async start(app: Express, router: Router): Promise { + public async handle(router: Router): Promise { router.use((req: Request, res: Response, next: NextFunction) => { if (res.headersSent) { return next(); @@ -22,19 +23,15 @@ export default class MaintenanceComponent extends ApplicationComponent { if (!this.application.isReady()) { res.header({'Retry-After': 60}); res.locals.refresh_after = 5; - throw new ServiceUnavailableHttpError('Watch My Stream is readying up. Please wait a few seconds...'); + throw new ServiceUnavailableHttpError(`${config.get('app.name')} is readying up. Please wait a few seconds...`); } if (!this.canServe()) { res.locals.refresh_after = 30; - throw new ServiceUnavailableHttpError('Watch My Stream is unavailable due to failure of dependent services.'); + throw new ServiceUnavailableHttpError(`${config.get('app.name')} is unavailable due to failure of dependent services.`); } next(); }); } - - public async stop(): Promise { - } - -} \ No newline at end of file +} diff --git a/src/components/MysqlComponent.ts b/src/components/MysqlComponent.ts index 0bf03e6..850ff1b 100644 --- a/src/components/MysqlComponent.ts +++ b/src/components/MysqlComponent.ts @@ -1,9 +1,9 @@ import ApplicationComponent from "../ApplicationComponent"; -import {Express, Router} from "express"; +import {Express} from "express"; import MysqlConnectionManager from "../db/MysqlConnectionManager"; -export default class MysqlComponent extends ApplicationComponent { - public async start(app: Express, router: Router): Promise { +export default class MysqlComponent extends ApplicationComponent { + public async start(_app: Express): Promise { await this.prepare('Mysql connection', () => MysqlConnectionManager.prepare()); } @@ -12,7 +12,7 @@ export default class MysqlComponent extends ApplicationComponent { } public canServe(): boolean { - return MysqlConnectionManager.pool !== undefined; + return MysqlConnectionManager.isReady(); } -} \ No newline at end of file +} diff --git a/src/components/NunjucksComponent.ts b/src/components/NunjucksComponent.ts index dff672a..a96ea61 100644 --- a/src/components/NunjucksComponent.ts +++ b/src/components/NunjucksComponent.ts @@ -1,38 +1,95 @@ -import nunjucks from "nunjucks"; +import nunjucks, {Environment} from "nunjucks"; import config from "config"; -import {Express, Router} from "express"; +import {Express, NextFunction, Request, Response, Router} from "express"; import ApplicationComponent from "../ApplicationComponent"; -import Controller from "../Controller"; -import {ServerError} from "../HttpError"; +import Controller, {RouteParams} from "../Controller"; +import * as querystring from "querystring"; +import {ParsedUrlQueryInput} from "querystring"; +import * as util from "util"; +import * as path from "path"; +import * as fs from "fs"; +import {logger} from "../Logger"; +import Middleware from "../Middleware"; -export default class NunjucksComponent extends ApplicationComponent { - public async start(app: Express, router: Router): Promise { - const env = nunjucks.configure('views', { +export default class NunjucksComponent extends ApplicationComponent { + private readonly viewsPath: string[]; + private environment?: Environment; + + public constructor(viewsPath: string[] = ['views']) { + super(); + this.viewsPath = viewsPath; + } + + public async start(app: Express): Promise { + let coreVersion = 'unknown'; + const file = fs.existsSync(path.join(__dirname, '../../package.json')) ? + path.join(__dirname, '../../package.json') : + path.join(__dirname, '../package.json'); + + try { + coreVersion = JSON.parse(fs.readFileSync(file).toString()).version; + } catch (e) { + logger.warn('Couldn\'t determine coreVersion.', e); + } + + const opts = { autoescape: true, - express: app, noCache: !config.get('view.cache'), throwOnUndefined: true, - }) - .addGlobal('route', (route: string, params: { [p: string]: string } | [] = [], absolute: boolean = false) => { - const path = Controller.route(route, params, absolute); - if (path === null) throw new ServerError(`Route ${route} not found.`); - return path; + }; + this.environment = new nunjucks.Environment([ + ...this.viewsPath.map(path => new nunjucks.FileSystemLoader(path, opts)), + new nunjucks.FileSystemLoader(path.join(__dirname, '../../../views'), opts), + new nunjucks.FileSystemLoader(path.join(__dirname, '../views'), opts), + ], opts) + .addGlobal('route', ( + route: string, + params: RouteParams = [], + query: ParsedUrlQueryInput = {}, + absolute: boolean = false, + ): string => { + return Controller.route(route, params, query, absolute); + }) + .addGlobal('app_version', this.getApp().getVersion()) + .addGlobal('core_version', coreVersion) + .addGlobal('querystring', querystring) + .addGlobal('app', config.get('app')) + + .addFilter('dump', (val) => { + return util.inspect(val); }) - .addGlobal('app_version', require('../package.json').version) .addFilter('hex', (v: number) => { return v.toString(16); }); + this.environment.express(app); app.set('view engine', 'njk'); - - router.use((req, res, next) => { - req.env = env; - res.locals.url = req.url; - res.locals.params = () => req.params; - next(); - }); } - public async stop(): Promise { + public async init(_router: Router): Promise { + this.use(NunjucksMiddleware); } -} \ No newline at end of file + public getEnvironment(): Environment { + if (!this.environment) throw new Error('Environment not initialized.'); + return this.environment; + } +} + +export class NunjucksMiddleware extends Middleware { + private env?: Environment; + + protected async handle(req: Request, res: Response, next: NextFunction): Promise { + this.env = this.app.as(NunjucksComponent).getEnvironment(); + res.locals.url = req.url; + res.locals.params = req.params; + res.locals.query = req.query; + res.locals.body = req.body; + + next(); + } + + public getEnvironment(): Environment { + if (!this.env) throw new Error('Environment not initialized.'); + return this.env; + } +} diff --git a/src/components/PreviousUrlComponent.ts b/src/components/PreviousUrlComponent.ts new file mode 100644 index 0000000..9e18ee7 --- /dev/null +++ b/src/components/PreviousUrlComponent.ts @@ -0,0 +1,54 @@ +import ApplicationComponent from "../ApplicationComponent"; +import {Router} from "express"; +import onFinished from "on-finished"; +import {logger} from "../Logger"; +import SessionComponent from "./SessionComponent"; + +export default class PreviousUrlComponent extends ApplicationComponent { + + public async handle(router: Router): Promise { + router.use((req, res, next) => { + req.getPreviousUrl = () => { + let url = req.header('referer'); + if (url) { + if (url.indexOf('://') >= 0) url = '/' + url.split('/').slice(3).join('/'); + if (url !== req.originalUrl) return url; + } + + if (this.getApp().asOptional(SessionComponent)) { + const session = req.getSessionOptional(); + url = session?.previousUrl; + if (url && url !== req.originalUrl) return url; + } + + return null; + }; + res.locals.getPreviousUrl = req.getPreviousUrl; + + req.getIntendedUrl = () => { + return req.query.redirect_uri?.toString() || null; + }; + + if (this.getApp().asOptional(SessionComponent)) { + const session = req.getSessionOptional(); + if (session && req.method === 'GET') { + onFinished(res, (err) => { + if (err) return; + + const contentType = res.getHeader('content-type'); + if (res.statusCode === 200 && + contentType && typeof contentType !== 'number' && contentType.indexOf('text/html') >= 0) { + session.previousUrl = req.originalUrl; + + session.save((err) => { + if (err) logger.error(err, 'Error while saving session'); + else logger.debug('Prev url set to', session.previousUrl); + }); + } + }); + } + } + next(); + }); + } +} diff --git a/src/components/RedirectBackComponent.ts b/src/components/RedirectBackComponent.ts deleted file mode 100644 index c3b9712..0000000 --- a/src/components/RedirectBackComponent.ts +++ /dev/null @@ -1,43 +0,0 @@ -import ApplicationComponent from "../ApplicationComponent"; -import {Express, Router} from "express"; -import onFinished from "on-finished"; -import Logger from "../Logger"; -import {ServerError} from "../HttpError"; - -export default class RedirectBackComponent extends ApplicationComponent { - public async start(app: Express, router: Router): Promise { - router.use((req, res, next) => { - if (!req.session) { - throw new Error('Session is unavailable.'); - } - - onFinished(res, (err) => { - if (!err && res.statusCode === 200) { - req.session!.previousUrl = req.originalUrl; - Logger.debug('Prev url set to', req.session!.previousUrl); - req.session!.save((err) => { - if (err) { - Logger.error(err, 'Error while saving session'); - } - }); - } - }); - - res.redirectBack = (defaultUrl?: string) => { - if (req.session && typeof req.session.previousUrl === 'string') { - res.redirect(req.session.previousUrl); - } else if (typeof defaultUrl === 'string') { - res.redirect(defaultUrl); - } else { - throw new ServerError('There is no previous url and no default redirection url was provided.'); - } - }; - - next(); - }); - } - - public async stop(): Promise { - } - -} \ No newline at end of file diff --git a/src/components/RedisComponent.ts b/src/components/RedisComponent.ts index f0efd3c..85363e8 100644 --- a/src/components/RedisComponent.ts +++ b/src/components/RedisComponent.ts @@ -1,31 +1,30 @@ import ApplicationComponent from "../ApplicationComponent"; -import {Express, Router} from "express"; +import {Express} from "express"; import redis, {RedisClient} from "redis"; import config from "config"; -import Logger from "../Logger"; +import {logger} from "../Logger"; import session, {Store} from "express-session"; -import connect_redis from "connect-redis"; +import CacheProvider from "../CacheProvider"; -const RedisStore = connect_redis(session); - -export default class RedisComponent extends ApplicationComponent { +export default class RedisComponent extends ApplicationComponent implements CacheProvider { private redisClient?: RedisClient; private store?: Store; - public async start(app: Express, router: Router): Promise { - this.redisClient = redis.createClient(config.get('redis.port'), config.get('redis.host'), {}); - this.redisClient.on('error', (err: any) => { - Logger.error(err, 'An error occurred with redis.'); + public async start(_app: Express): Promise { + this.redisClient = redis.createClient(config.get('redis.port'), config.get('redis.host'), { + password: config.has('redis.password') ? config.get('redis.password') : undefined, }); - this.store = new RedisStore({ - client: this.redisClient, - prefix: 'wms-sess:', + this.redisClient.on('error', (err: Error) => { + logger.error(err, 'An error occurred with redis.'); }); + + this.store = new RedisStore(this); } public async stop(): Promise { - if (this.redisClient) { - await this.close('Redis connection', this.redisClient, this.redisClient.quit); + const redisClient = this.redisClient; + if (redisClient) { + await this.close('Redis connection', callback => redisClient.quit(callback)); } } @@ -37,4 +36,112 @@ export default class RedisComponent extends ApplicationComponent { public canServe(): boolean { return this.redisClient !== undefined && this.redisClient.connected; } -} \ No newline at end of file + + public async get(key: string, defaultValue?: T): Promise { + return await new Promise((resolve, reject) => { + if (!this.redisClient) { + reject(`Redis client was not initialized.`); + return; + } + + this.redisClient.get(key, (err, val) => { + if (err) { + reject(err); + return; + } + resolve((val || defaultValue || undefined) as T); + }); + }); + } + + public async has(key: string): Promise { + return await this.get(key) !== undefined; + } + + public async forget(key: string): Promise { + return await new Promise((resolve, reject) => { + if (!this.redisClient) { + reject(`Redis client was not initialized.`); + return; + } + + this.redisClient.del(key, (err) => { + if (err) { + reject(err); + return; + } + + resolve(); + }); + }); + } + + public async remember(key: string, value: string, ttl: number): Promise { + return await new Promise((resolve, reject) => { + if (!this.redisClient) { + reject(`Redis client was not initialized.`); + return; + } + + this.redisClient.psetex(key, ttl, value, (err) => { + if (err) return reject(err); + resolve(); + }); + }); + } + + public async persist(key: string, ttl: number): Promise { + return await new Promise((resolve, reject) => { + if (!this.redisClient) { + reject(`Redis client was not initialized.`); + return; + } + + this.redisClient.pexpire(key, ttl, (err) => { + if (err) return reject(err); + resolve(); + }); + }); + } +} + +class RedisStore extends Store { + private readonly redisComponent: RedisComponent; + + public constructor(redisComponent: RedisComponent) { + super(); + this.redisComponent = redisComponent; + } + + public get(sid: string, callback: (err?: Error, session?: (session.SessionData | null)) => void): void { + this.redisComponent.get(`-session:${sid}`) + .then(value => { + if (value) { + this.redisComponent.persist(`-session:${sid}`, config.get('session.cookie.maxAge')) + .then(() => { + callback(undefined, JSON.parse(value)); + }) + .catch(callback); + } else { + callback(undefined, null); + } + }) + .catch(callback); + } + + public set(sid: string, session: session.SessionData, callback?: (err?: Error) => void): void { + this.redisComponent.remember(`-session:${sid}`, JSON.stringify(session), config.get('session.cookie.maxAge')) + .then(() => { + if (callback) callback(); + }) + .catch(callback); + } + + public destroy(sid: string, callback?: (err?: Error) => void): void { + this.redisComponent.forget(`-session:${sid}`) + .then(() => { + if (callback) callback(); + }) + .catch(callback); + } +} diff --git a/src/components/ServeStaticDirectoryComponent.ts b/src/components/ServeStaticDirectoryComponent.ts index 5573c37..191ac28 100644 --- a/src/components/ServeStaticDirectoryComponent.ts +++ b/src/components/ServeStaticDirectoryComponent.ts @@ -1,26 +1,24 @@ import ApplicationComponent from "../ApplicationComponent"; -import express, {Express, Router} from "express"; +import express, {Router} from "express"; import {PathParams} from "express-serve-static-core"; +import * as path from "path"; -export default class ServeStaticDirectoryComponent extends ApplicationComponent { +export default class ServeStaticDirectoryComponent extends ApplicationComponent { private readonly root: string; private readonly path?: PathParams; - constructor(root: string, routePath?: PathParams) { + public constructor(root: string, routePath?: PathParams) { super(); - this.root = root; + this.root = path.join(__dirname, '../../../', root); this.path = routePath; } - public async start(app: Express, router: Router): Promise { - if (typeof this.path !== 'undefined') { + public async init(router: Router): Promise { + if (this.path) { router.use(this.path, express.static(this.root, {maxAge: 1000 * 3600 * 72})); } else { router.use(express.static(this.root, {maxAge: 1000 * 3600 * 72})); } } - public async stop(): Promise { - } - -} \ No newline at end of file +} diff --git a/src/components/SessionComponent.ts b/src/components/SessionComponent.ts index 696be18..1c86fe6 100644 --- a/src/components/SessionComponent.ts +++ b/src/components/SessionComponent.ts @@ -3,23 +3,30 @@ import session from "express-session"; import config from "config"; import RedisComponent from "./RedisComponent"; import flash from "connect-flash"; -import {Express, Router} from "express"; +import {Router} from "express"; +import SecurityError from "../SecurityError"; -export default class SessionComponent extends ApplicationComponent { +export default class SessionComponent extends ApplicationComponent { private readonly storeComponent: RedisComponent; - public constructor(storeComponent: RedisComponent) { super(); this.storeComponent = storeComponent; } - public async start(app: Express, router: Router): Promise { + public async checkSecuritySettings(): Promise { + this.checkSecurityConfigField('session.secret'); + if (!config.get('session.cookie.secure')) { + throw new SecurityError('Cannot set cookie secure field to false.'); + } + } + + public async init(router: Router): Promise { router.use(session({ saveUninitialized: true, secret: config.get('session.secret'), store: this.storeComponent.getStore(), - resave: true, + resave: false, cookie: { httpOnly: true, secure: config.get('session.cookie.secure'), @@ -30,28 +37,61 @@ export default class SessionComponent extends ApplicationComponent { router.use(flash()); router.use((req, res, next) => { - if (!req.session) { - throw new Error('Session is unavailable.'); + // Request session getters + req.getSessionOptional = () => { + return req.session; + }; + req.getSession = () => { + const session = req.getSessionOptional(); + if (!session) throw new Error('Session not initialized.'); + return session; + }; + + // Session persistence + const session = req.getSession(); + if (session.persistent) { + session.cookie.maxAge = config.get('session.cookie.maxAge'); + } else { + session.cookie.maxAge = session.cookie.expires = undefined; } - res.locals.session = req.session; + // Views session local + res.locals.session = session; - let _flash: any = null; - res.locals.flash = () => { - if (!_flash) { - _flash = { + // Views flash function + const _flash: FlashStorage = {}; + res.locals.flash = (key?: string): FlashMessages | unknown[] => { + if (key !== undefined) { + if (_flash[key] === undefined) _flash[key] = req.flash(key); + return _flash[key] || []; + } + + if (_flash._messages === undefined) { + _flash._messages = { info: req.flash('info'), success: req.flash('success'), warning: req.flash('warning'), error: req.flash('error'), }; } - return _flash; + return _flash._messages; }; next(); }); } +} - public async stop(): Promise { - } -} \ No newline at end of file +export type FlashMessages = { + [k: string]: unknown[] | undefined +}; + +export type DefaultFlashMessages = FlashMessages & { + info?: unknown[] | undefined; + success?: unknown[] | undefined; + warning?: unknown[] | undefined; + error?: unknown[] | undefined; +}; + +type FlashStorage = FlashMessages & { + _messages?: DefaultFlashMessages, +}; diff --git a/src/components/WebSocketServerComponent.ts b/src/components/WebSocketServerComponent.ts index 4081e96..98824cb 100644 --- a/src/components/WebSocketServerComponent.ts +++ b/src/components/WebSocketServerComponent.ts @@ -1,7 +1,7 @@ import ApplicationComponent from "../ApplicationComponent"; -import {Express, Request, Router} from "express"; +import {Express, Request} from "express"; import WebSocket, {Server as WebSocketServer} from "ws"; -import Logger from "../Logger"; +import {logger} from "../Logger"; import cookie from "cookie"; import cookieParser from "cookie-parser"; import config from "config"; @@ -9,29 +9,28 @@ import ExpressAppComponent from "./ExpressAppComponent"; import Application from "../Application"; import RedisComponent from "./RedisComponent"; import WebSocketListener from "../WebSocketListener"; +import NunjucksComponent from "./NunjucksComponent"; -export default class WebSocketServerComponent extends ApplicationComponent { - private readonly application: Application; - private readonly expressAppComponent: ExpressAppComponent; - private readonly storeComponent: RedisComponent; - +export default class WebSocketServerComponent extends ApplicationComponent { private wss?: WebSocket.Server; - constructor(application: Application, expressAppComponent: ExpressAppComponent, storeComponent: RedisComponent) { + public constructor( + private readonly application: Application, + private readonly expressAppComponent: ExpressAppComponent, + private readonly storeComponent: RedisComponent, + private readonly nunjucksComponent?: NunjucksComponent, + ) { super(); - this.expressAppComponent = expressAppComponent; - this.application = application; - this.storeComponent = storeComponent; } - public async start(app: Express, router: Router): Promise { - const listeners: { [p: string]: WebSocketListener } = this.application.getWebSocketListeners(); + public async start(_app: Express): Promise { + const listeners: { [p: string]: WebSocketListener } = this.application.getWebSocketListeners(); this.wss = new WebSocketServer({ server: this.expressAppComponent.getServer(), }, () => { - Logger.info(`Websocket server started over webserver.`); + logger.info(`Websocket server started over webserver.`); }).on('error', (err) => { - Logger.error(err, 'An error occurred in the websocket server.'); + logger.error(err, 'An error occurred in the websocket server.'); }).on('connection', (socket, request) => { const listener = request.url ? listeners[request.url] : null; @@ -39,11 +38,13 @@ export default class WebSocketServerComponent extends ApplicationComponent socket.close(1002, `Path not found ${request.url}`); return; } else if (!request.headers.cookie) { - socket.close(1002, `Can't process request without cookies.`); + listener.handle(socket, request, null).catch(err => { + logger.error(err, 'Error in websocket listener.'); + }); return; } - Logger.debug(`Websocket on ${request.url}`); + logger.debug(`Websocket on ${request.url}`); const cookies = cookie.parse(request.headers.cookie); const sid = cookieParser.signedCookie(cookies['connect.sid'], config.get('session.secret')); @@ -56,7 +57,7 @@ export default class WebSocketServerComponent extends ApplicationComponent const store = this.storeComponent.getStore(); store.get(sid, (err, session) => { if (err || !session) { - Logger.error(err, 'Error while initializing session in websocket.'); + logger.error(err, 'Error while initializing session in websocket.'); socket.close(1011); return; } @@ -64,16 +65,22 @@ export default class WebSocketServerComponent extends ApplicationComponent session.id = sid; store.createSession(request, session); - listener.handle(socket, request, session).catch(err => { - Logger.error(err, 'Error in websocket listener.'); + listener.handle(socket, request, (request).session).catch(err => { + logger.error(err, 'Error in websocket listener.'); }); }); }); + + const env = this.nunjucksComponent?.getEnvironment(); + if (env) { + env.addGlobal('websocketUrl', config.get('public_websocket_url')); + } } public async stop(): Promise { - if (this.wss) { - await this.close('WebSocket server', this.wss, this.wss.close); + const wss = this.wss; + if (wss) { + await this.close('WebSocket server', callback => wss.close(callback)); } } -} \ No newline at end of file +} diff --git a/src/db/Migration.ts b/src/db/Migration.ts index 34b3c4a..cfa94ff 100644 --- a/src/db/Migration.ts +++ b/src/db/Migration.ts @@ -1,15 +1,39 @@ +import {Connection} from "mysql"; +import MysqlConnectionManager from "./MysqlConnectionManager"; +import {Type} from "../Utils"; + export default abstract class Migration { public readonly version: number; + private currentConnection?: Connection; - constructor(version: number) { + public constructor(version: number) { this.version = version; } - async shouldRun(currentVersion: number): Promise { + public async shouldRun(currentVersion: number): Promise { return this.version > currentVersion; } - abstract async install(): Promise; + public abstract install(): Promise; - abstract async rollback(): Promise; -} \ No newline at end of file + public abstract rollback(): Promise; + + public registerModels?(): void; + + protected async query(queryString: string): Promise { + await MysqlConnectionManager.query(queryString, undefined, this.getCurrentConnection()); + } + + protected getCurrentConnection(): Connection { + if (!this.currentConnection) throw new Error('No current connection set.'); + return this.currentConnection; + } + + public setCurrentConnection(connection: Connection | null): void { + this.currentConnection = connection || undefined; + } +} + +export interface MigrationType extends Type { + new(version: number): M; +} diff --git a/src/db/Model.ts b/src/db/Model.ts index ea0ef37..399d407 100644 --- a/src/db/Model.ts +++ b/src/db/Model.ts @@ -1,311 +1,245 @@ -import MysqlConnectionManager, {query} from "./MysqlConnectionManager"; +import MysqlConnectionManager from "./MysqlConnectionManager"; import Validator from "./Validator"; import {Connection} from "mysql"; -import Query from "./Query"; +import ModelComponent from "./ModelComponent"; +import {Type} from "../Utils"; +import ModelFactory, {PrimaryKeyValue} from "./ModelFactory"; +import ModelRelation from "./ModelRelation"; +import ModelQuery, {ModelFieldData, ModelQueryResult, QueryFields} from "./ModelQuery"; import {Request} from "express"; -import Pagination from "../Pagination"; +import Extendable from "../Extendable"; -export default abstract class Model { - public static async getById(id: number): Promise { - const cachedModel = ModelCache.get(this.table, id); - if (cachedModel?.constructor === this) { - return cachedModel; - } - - const models = await this.models(this.select().where('id', id).first()); - return models.length > 0 ? models[0] : null; +export default abstract class Model implements Extendable> { + public static get table(): string { + const single = this.name + .replace(/(?:^|\.?)([A-Z])/g, (x, y) => '_' + y.toLowerCase()) + .replace(/^_/, ''); + return single + 's'; } - public static async paginate(request: Request, perPage: number = 20): Promise { - let page = request.params.page ? parseInt(request.params.page) : 1; - let query: Query = this.select().limit(perPage, (page - 1) * perPage).withTotalRowCount(); - if (request.params.sortBy) { - const dir = request.params.sortDirection; - query = query.sortBy(request.params.sortBy, dir === 'ASC' || dir === 'DESC' ? dir : undefined); - } else { - query = query.sortBy('id'); - } - const models = await this.models(query); - // @ts-ignore - models.pagination = new Pagination(models, page, perPage, models.totalCount); - return models; + public static getPrimaryKeyFields(): string[] { + return ['id']; } - protected static select(...fields: string[]): Query { - return Query.select(this.table, ...fields); + public static create(this: ModelType, data: Pick): M { + return ModelFactory.get(this).create(data, true); } - protected static update(data: { [key: string]: any }): Query { - return Query.update(this.table, data); + public static select(this: ModelType, ...fields: QueryFields): ModelQuery { + return ModelFactory.get(this).select(...fields); } - protected static delete(): Query { - return Query.delete(this.table); + public static update(this: ModelType, data: Pick): ModelQuery { + return ModelFactory.get(this).update(data); } - protected static async models(query: Query): Promise { - const results = await query.execute(); - const models: T[] = []; - const factory = this.getFactory(); - for (const result of results.results) { - const cachedModel = ModelCache.get(this.table, result.id); - if (cachedModel && cachedModel.constructor === this) { - cachedModel.updateWithData(result); - models.push(cachedModel); - } else { - models.push(factory(result)); + public static delete(this: ModelType): ModelQuery { + return ModelFactory.get(this).delete(); + } + + public static async getById(this: ModelType, ...id: PrimaryKeyValue[]): Promise { + return await ModelFactory.get(this).getById(...id); + } + + public static async paginate( + this: ModelType, + request: Request, + perPage: number = 20, + query?: ModelQuery, + ): Promise> { + return await ModelFactory.get(this).paginate(request, perPage, query); + } + + + protected readonly _factory: ModelFactory; + private readonly _components: ModelComponent[] = []; + private readonly _validators: { [K in keyof this]?: Validator | undefined } = {}; + private _exists: boolean; + + [key: string]: ModelFieldData; + + public constructor(factory: ModelFactory, isNew: boolean) { + if (!(factory instanceof ModelFactory)) throw new Error('Cannot instantiate model directly.'); + this._factory = factory; + this.init?.(); + this._exists = !isNew; + } + + protected init?(): void; + + protected setValidation(propertyName: K): Validator { + const validator = new Validator(); + this._validators[propertyName] = validator; + return validator; + } + + public addComponent(modelComponent: ModelComponent): void { + modelComponent.applyToModel(); + this._components.push(modelComponent); + } + + public as>(type: Type): C { + for (const component of this._components) { + if (component instanceof type) { + return this as unknown as C; } } - // @ts-ignore - models.totalCount = results.foundRows; - return models; + + throw new Error(`Component ${type.name} was not initialized for this ${this.constructor.name}.`); } - public static async loadRelation(models: T[], relation: string, model: Function, localField: string) { - const loadMap: { [p: number]: (model: T) => void } = {}; - const ids = models.map(m => { - m.relations[relation] = null; - if (m[localField]) loadMap[m[localField]] = v => m.relations[relation] = v; - return m[localField]; - }).filter(id => id); - for (const v of await (model).models((model).select().whereIn('id', ids))) { - loadMap[v.id!](v); - } - } - - private static getFactory(factory?: ModelFactory): ModelFactory { - if (factory === undefined) { - factory = (this).FACTORY; - if (factory === undefined) factory = data => new (this)(data); - } - return factory; - } - - - protected readonly properties: ModelProperty[] = []; - private readonly relations: { [p: string]: (Model | null) } = {}; - public id?: number; - - [key: string]: any; - - public constructor(data: any) { - this.defineProperty('id', new Validator()); - this.defineProperties(); - this.updateWithData(data); - } - - protected abstract defineProperties(): void; - - protected defineProperty(name: string, validator?: Validator | RegExp) { - if (validator === undefined) validator = new Validator(); - if (validator instanceof RegExp) { - const regexp = validator; - validator = new Validator().regexp(regexp); + public asOptional>(type: Type): C | null { + for (const component of this._components) { + if (component instanceof type) { + return this as unknown as C; + } } - const prop = new ModelProperty(name, validator); - this.properties.push(prop); - Object.defineProperty(this, name, { - get: () => prop.value, - set: (value: T) => prop.value = value, - }); + return null; } - private updateWithData(data: any) { - this.id = data['id']; - - for (const prop of this.properties) { - if (data[prop.name] !== undefined) { - this[prop.name] = data[prop.name]; + public updateWithData(data: Pick | Record): void { + for (const property of this._properties) { + if (data[property] !== undefined) { + this[property] = data[property] as this[keyof this & string]; } } } - protected async beforeSave(exists: boolean, connection: Connection): Promise { - } + /** + * Override this to automatically fill obvious missing data i.e. from relation or default value that are fetched + * asynchronously. + */ + protected async autoFill?(): Promise; - protected async afterSave(): Promise { - } + protected async beforeSave?(connection: Connection): Promise; + + protected async afterSave?(): Promise; public async save(connection?: Connection, postHook?: (callback: () => Promise) => void): Promise { + if (connection && !postHook) throw new Error('If connection is provided, postHook must be provided too.'); + + await this.autoFill?.(); await this.validate(false, connection); - const exists = await this.exists(); - let needs_full_update = false; - - if (connection) { - needs_full_update = await this.saveTransaction(connection, exists, needs_full_update); - } else { - needs_full_update = await MysqlConnectionManager.wrapTransaction(async connection => this.saveTransaction(connection, exists, needs_full_update)); - } + const needs_full_update = connection ? + await this.saveTransaction(connection) : + await MysqlConnectionManager.wrapTransaction(async connection => await this.saveTransaction(connection)); const callback = async () => { if (needs_full_update) { - this.updateWithData((await (this.constructor).select().where('id', this.id!).first().execute()).results[0]); + const query = this._factory.select(); + for (const field of this._factory.getPrimaryKeyFields()) { + query.where(field, this[field]); + } + query.limit(1); + const result = await query.execute(connection); + this.updateWithData(result.results[0]); } - if (!exists) { - this.cache(); - } - - await this.afterSave(); + await this.afterSave?.(); }; - if (connection) { - postHook!(callback); + if (postHook) { + postHook(callback); } else { await callback(); } } - private async saveTransaction(connection: Connection, exists: boolean, needs_full_update: boolean): Promise { + private async saveTransaction(connection: Connection): Promise { // Before save - await this.beforeSave(exists, connection); - if (exists && this.hasOwnProperty('updated_at')) { + await this.beforeSave?.(connection); + if (!this.exists() && this.hasProperty('created_at')) { + this.created_at = new Date(); + } + if (this.exists() && this.hasProperty('updated_at')) { this.updated_at = new Date(); } - const props = []; - const values = []; + let needsFullUpdate = false; - if (exists) { - for (const prop of this.properties) { - if (prop.value !== undefined) { - props.push(prop.name + '=?'); - values.push(prop.value); - } else { - needs_full_update = true; - } - } - values.push(this.id); - await query(`UPDATE ${this.table} SET ${props.join(',')} WHERE id=?`, values, connection); - } else { - const props_holders = []; - for (const prop of this.properties) { - if (prop.value !== undefined) { - props.push(prop.name); - props_holders.push('?'); - values.push(prop.value); - } else { - needs_full_update = true; - } - } - const result = await query(`INSERT INTO ${this.table} (${props.join(', ')}) VALUES(${props_holders.join(', ')})`, values, connection); + const data: { [K in keyof this]?: this[K] } = {}; + for (const property of this._properties) { + const value = this[property]; - this.id = result.other.insertId; + if (value === undefined) needsFullUpdate = true; + else data[property] = value; } - return needs_full_update; - } + if (this.exists()) { + const query = this._factory.update(data); + for (const indexField of this._factory.getPrimaryKeyFields()) { + query.where(indexField, this[indexField]); + } + await query.execute(connection); + } else { + const query = this._factory.insert(data); + const result = await query.execute(connection); - public static get table(): string { - return this.name - .replace(/(?:^|\.?)([A-Z])/g, (x, y) => '_' + y.toLowerCase()) - .replace(/^_/, '') - + 's'; - } + if (this.hasProperty('id')) this.id = Number(result.other?.insertId); + this._exists = true; + } - public get table(): string { - // @ts-ignore - return this.constructor.table; - } - - public async exists(): Promise { - if (!this.id) return false; - - const result = await query(`SELECT 1 FROM ${this.table} WHERE id=? LIMIT 1`, [ - this.id, - ]); - return result.results.length > 0; + return needsFullUpdate; } public async delete(): Promise { - if (!(await this.exists())) throw new Error('This model instance doesn\'t exist in DB.'); + if (!await this.exists()) throw new Error('This model instance doesn\'t exist in DB.'); - await query(`DELETE FROM ${this.table} WHERE id=?`, [ - this.id, - ]); - ModelCache.forget(this); - this.id = undefined; + const query = this._factory.delete(); + for (const indexField of this._factory.getPrimaryKeyFields()) { + query.where(indexField, this[indexField]); + } + await query.execute(); + this._exists = false; } public async validate(onlyFormat: boolean = false, connection?: Connection): Promise { - return await Promise.all(this.properties.map(prop => prop.validate(onlyFormat, connection))); + return await Promise.all(this._properties.map( + prop => this._validators[prop]?.execute(prop, this[prop], onlyFormat, connection), + )); } - private cache() { - ModelCache.cache(this); + public exists(): boolean { + return this._exists; } - protected relation(name: string): T | null { - if (this.relations[name] === undefined) throw new Error('Model not loaded'); - return this.relations[name]; - } -} - -export interface ModelFactory { - (data: any): T; -} - -class ModelProperty { - public readonly name: string; - private readonly validator: Validator; - private val?: T; - - constructor(name: string, validator: Validator) { - this.name = name; - this.validator = validator; - } - - public async validate(onlyFormat: boolean, connection?: Connection): Promise { - return await this.validator.execute(this.name, this.value, onlyFormat, connection); - } - - public get value(): T | undefined { - return this.val; - } - - public set value(val: T | undefined) { - this.val = val; - } -} - -export class ModelCache { - private static readonly caches: { - [key: string]: { - [key: number]: Model + public equals(model: this): boolean { + for (const field of this._factory.getPrimaryKeyFields()) { + if (this[field] !== model[field]) return false; } - } = {}; - - public static cache(instance: Model) { - if (instance.id === undefined) throw new Error('Cannot cache an instance with an undefined id.'); - - let tableCache = this.caches[instance.table]; - if (!tableCache) tableCache = this.caches[instance.table] = {}; - - if (!tableCache[instance.id]) tableCache[instance.id] = instance; + return true; } - public static forget(instance: Model) { - if (instance.id === undefined) throw new Error('Cannot forget an instance with an undefined id.'); - - let tableCache = this.caches[instance.table]; - if (!tableCache) return; - - if (tableCache[instance.id]) delete tableCache[instance.id]; + public get table(): string { + return this._factory.table; } - public static all(table: string): { - [key: number]: Model - } | undefined { - return this.caches[table]; + private get _properties(): (keyof this & string)[] { + return Object.getOwnPropertyNames(this).filter(p => { + return !p.startsWith('_') && + typeof this[p] !== 'function' && + !(this[p] instanceof ModelRelation); + }); } - public static get(table: string, id: number): Model | undefined { - const tableCache = this.all(table); - if (!tableCache) return undefined; - return tableCache[id]; + private hasProperty(key: string | number | symbol): key is keyof this { + return typeof key === 'string' && this._properties.indexOf(key) >= 0; + } + + public getOrFail(k: K): NonNullable { + if (!this[k]) throw new Error(k + ' not initialized.'); + return this[k] as NonNullable; } } -export const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/; \ No newline at end of file +export interface ModelType extends Type { + table: string; + + new(factory: ModelFactory, isNew: boolean): M; + + getPrimaryKeyFields(): (keyof M & string)[]; + + select(this: ModelType, ...fields: QueryFields): ModelQuery; +} diff --git a/src/db/ModelComponent.ts b/src/db/ModelComponent.ts new file mode 100644 index 0000000..7983749 --- /dev/null +++ b/src/db/ModelComponent.ts @@ -0,0 +1,48 @@ +import Model from "./Model"; +import Validator from "./Validator"; +import {getMethods} from "../Utils"; +import {ModelFieldData} from "./ModelQuery"; + +export default abstract class ModelComponent { + protected readonly _model: M; + private readonly _validators: { [K in keyof this]?: Validator } = {}; + + [key: string]: ModelFieldData; + + public constructor(model: M) { + this._model = model; + } + + public applyToModel(): void { + this.init?.(); + + const model = this._model as Model; + + for (const property of this._properties) { + if (!property.startsWith('_')) { + model[property] = this[property]; + model['_validators'][property] = this._validators[property] as Validator | undefined; + } + } + + for (const method of getMethods(this)) { + if (!method.startsWith('_') && + ['init', 'setValidation'].indexOf(method) < 0 && + model[method] === undefined) { + model[method] = this[method]; + } + } + } + + protected init?(): void; + + protected setValidation(propertyName: K): Validator { + const validator = new Validator(); + this._validators[propertyName] = validator; + return validator; + } + + private get _properties(): string[] { + return Object.getOwnPropertyNames(this).filter(p => !p.startsWith('_')); + } +} diff --git a/src/db/ModelFactory.ts b/src/db/ModelFactory.ts new file mode 100644 index 0000000..6d91c81 --- /dev/null +++ b/src/db/ModelFactory.ts @@ -0,0 +1,104 @@ +import ModelComponent from "./ModelComponent"; +import Model, {ModelType} from "./Model"; +import ModelQuery, {ModelQueryResult, QueryFields} from "./ModelQuery"; +import {Request} from "express"; + +export default class ModelFactory { + private static readonly factories: { [modelType: string]: ModelFactory | undefined } = {}; + + public static register(modelType: ModelType): void { + if (this.factories[modelType.name]) throw new Error(`Factory for type ${modelType.name} already defined.`); + this.factories[modelType.name] = new ModelFactory(modelType) as unknown as ModelFactory; + } + + public static get(modelType: ModelType): ModelFactory { + const factory = this.factories[modelType.name]; + if (!factory) throw new Error(`No factory registered for ${modelType.name}.`); + return factory as unknown as ModelFactory; + } + + public static has(modelType: ModelType): boolean { + return !!this.factories[modelType.name]; + } + + private readonly modelType: ModelType; + private readonly components: ModelComponentFactory[] = []; + + protected constructor(modelType: ModelType) { + this.modelType = modelType; + } + + public addComponent(modelComponentFactory: ModelComponentFactory): void { + this.components.push(modelComponentFactory); + } + + public hasComponent(modelComponentFactory: ModelComponentFactory): boolean { + return !!this.components.find(c => c === modelComponentFactory); + } + + public create(data: Pick, isNewModel: boolean): M { + const model = new this.modelType(this as unknown as ModelFactory, isNewModel); + for (const component of this.components) { + model.addComponent(new component(model)); + } + model.updateWithData(data); + return model; + } + + public get table(): string { + return this.modelType.table; + } + + public select(...fields: QueryFields): ModelQuery { + return ModelQuery.select(this, ...fields); + } + + public insert(data: Pick): ModelQuery { + return ModelQuery.insert(this, data); + } + + public update(data: Pick): ModelQuery { + return ModelQuery.update(this, data); + } + + public delete(): ModelQuery { + return ModelQuery.delete(this); + } + + public getPrimaryKeyFields(): (keyof M & string)[] { + return this.modelType.getPrimaryKeyFields(); + } + + public getPrimaryKey(modelData: Pick): Pick[keyof M & string][] { + return this.getPrimaryKeyFields().map(f => modelData[f]); + } + + public getPrimaryKeyString(modelData: Pick): string { + return this.getPrimaryKey(modelData).join(','); + } + + public async getById(...id: PrimaryKeyValue[]): Promise { + let query = this.select(); + const primaryKeyFields = this.getPrimaryKeyFields(); + for (let i = 0; i < primaryKeyFields.length; i++) { + query = query.where(primaryKeyFields[i], id[i]); + } + return await query.first(); + } + + public async paginate(request: Request, perPage: number = 20, query?: ModelQuery): Promise> { + const page = request.params.page ? parseInt(request.params.page) : 1; + if (!query) query = this.select(); + if (request.params.sortBy) { + const dir = request.params.sortDirection; + query = query.sortBy(request.params.sortBy, dir === 'ASC' || dir === 'DESC' ? dir : undefined); + } else { + query = query.sortBy('id'); + } + return await query.paginate(page, perPage); + } +} + +export type ModelComponentFactory = new (model: M) => ModelComponent; + +export type PrimaryKeyValue = string | number | boolean | null | undefined; diff --git a/src/db/ModelQuery.ts b/src/db/ModelQuery.ts new file mode 100644 index 0000000..472744d --- /dev/null +++ b/src/db/ModelQuery.ts @@ -0,0 +1,557 @@ +import {isQueryVariable, query, QueryResult, QueryVariable} from "./MysqlConnectionManager"; +import {Connection} from "mysql"; +import Model from "./Model"; +import Pagination from "../Pagination"; +import ModelRelation, {RelationDatabaseProperties} from "./ModelRelation"; +import ModelFactory from "./ModelFactory"; + + +export default class ModelQuery implements WhereFieldConsumer { + public static select(factory: ModelFactory, ...fields: QueryFields): ModelQuery { + fields = fields.map(v => v === '' ? new SelectFieldValue('none', 1, true) : v); + return new ModelQuery(QueryType.SELECT, factory, fields.length > 0 ? fields : ['*']); + } + + public static insert(factory: ModelFactory, data: Pick): ModelQuery { + const fields = []; + for (const key of Object.keys(data)) { + fields.push(new FieldValue(key, data[key], false)); + } + return new ModelQuery(QueryType.INSERT, factory, fields); + } + + public static update(factory: ModelFactory, data: Pick): ModelQuery { + const fields = []; + for (const key of Object.keys(data)) { + fields.push(new FieldValue(inputToFieldOrValue(key, factory.table), data[key], false)); + } + return new ModelQuery(QueryType.UPDATE, factory, fields); + } + + public static delete(factory: ModelFactory): ModelQuery { + return new ModelQuery(QueryType.DELETE, factory); + } + + private readonly type: QueryType; + private readonly factory: ModelFactory; + private readonly table: string; + private readonly fields: QueryFields; + private _leftJoin?: string; + private _leftJoinAlias?: string; + private _leftJoinOn: WhereFieldValue[] = []; + private _where: (WhereFieldValue | WhereFieldValueGroup)[] = []; + private _limit?: number; + private _offset?: number; + private _sortBy?: string; + private _sortDirection?: 'ASC' | 'DESC'; + private readonly relations: string[] = []; + private readonly subRelations: { [relation: string]: string[] | undefined } = {}; + private _pivot?: string[]; + private _union?: ModelQueryUnion; + private _recursiveRelation?: RelationDatabaseProperties; + private _reverseRecursiveRelation?: boolean; + + private constructor(type: QueryType, factory: ModelFactory, fields?: QueryFields) { + this.type = type; + this.factory = factory; + this.table = factory.table; + this.fields = fields || []; + } + + public leftJoin(table: string, alias?: string): this { + this._leftJoin = table; + this._leftJoinAlias = alias; + return this; + } + + public on( + field1: string, + field2: string, + test: WhereTest = WhereTest.EQ, + operator: WhereOperator = WhereOperator.AND, + ): this { + this._leftJoinOn.push(new WhereFieldValue( + inputToFieldOrValue(field1), inputToFieldOrValue(field2), true, test, operator, + )); + return this; + } + + public where( + field: string, + value: ModelFieldData, + test: WhereTest = WhereTest.EQ, + operator: WhereOperator = WhereOperator.AND, + ): this { + this._where.push(new WhereFieldValue(field, value, false, test, operator)); + return this; + } + + public groupWhere( + setter: (query: WhereFieldConsumer) => void, + operator: WhereOperator = WhereOperator.AND, + ): this { + this._where.push(new WhereFieldValueGroup(this.collectWheres(setter), operator)); + return this; + } + + private collectWheres(setter: (query: WhereFieldConsumer) => void): (WhereFieldValue | WhereFieldValueGroup)[] { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const query = this; + const wheres: (WhereFieldValue | WhereFieldValueGroup)[] = []; + setter({ + where( + field: string, + value: ModelFieldData, + test: WhereTest = WhereTest.EQ, + operator: WhereOperator = WhereOperator.AND, + ) { + wheres.push(new WhereFieldValue(field, value, false, test, operator)); + return this; + }, + groupWhere( + setter: (query: WhereFieldConsumer) => void, + operator: WhereOperator = WhereOperator.AND, + ) { + wheres.push(new WhereFieldValueGroup(query.collectWheres(setter), operator)); + return this; + }, + }); + return wheres; + } + + public limit(limit: number, offset: number = 0): this { + this._limit = limit; + this._offset = offset; + return this; + } + + public sortBy(field: string, direction: SortDirection = 'ASC', raw: boolean = false): this { + this._sortBy = raw ? field : inputToFieldOrValue(field); + this._sortDirection = direction; + return this; + } + + /** + * @param relations The relations field names to eagerload. To load nested relations, separate fields with '.' + * (i.e.: "author.roles.permissions" loads authors, their roles, and the permissions of these roles) + */ + public with(...relations: string[]): this { + relations.forEach(relation => { + const parts = relation.split('.'); + if (this.relations.indexOf(parts[0]) < 0) this.relations.push(parts[0]); + if (parts.length > 1) { + if (!this.subRelations[parts[0]]) this.subRelations[parts[0]] = []; + this.subRelations[parts[0]]?.push(parts.slice(1).join('.')); + } + }); + return this; + } + + public pivot(...fields: string[]): this { + this._pivot = fields; + return this; + } + + public union( + query: ModelQuery, + sortBy: string, direction: SortDirection = 'ASC', + raw: boolean = false, + limit?: number, + offset?: number, + ): this { + if (this.type !== QueryType.SELECT) throw new Error('Union queries are only implemented with SELECT.'); + + this._union = { + query: query, + sortBy: raw ? sortBy : inputToFieldOrValue(sortBy), + direction: direction, + limit: limit, + offset: offset, + }; + return this; + } + + public recursive(relation: RelationDatabaseProperties, reverse: boolean): this { + if (this.type !== QueryType.SELECT) throw new Error('Recursive queries are only implemented with SELECT.'); + this._recursiveRelation = relation; + this._reverseRecursiveRelation = reverse; + return this; + } + + public toString(final: boolean = false): string { + let query = ''; + + if (this._pivot) this.fields.push(...this._pivot); + + // Prevent wildcard and fields from conflicting + const fields = this.fields.map(f => { + const field = f.toString(); + if (field.startsWith('(')) return f; // Skip sub-queries + return inputToFieldOrValue(field, this.table); + }).join(','); + + let join = ''; + if (this._leftJoin) { + join = ` LEFT JOIN \`${this._leftJoin}\`` + + (this._leftJoinAlias ? ` AS \`${this._leftJoinAlias}\`` : '') + + ` ON ${this._leftJoinOn[0]}`; + for (let i = 1; i < this._leftJoinOn.length; i++) { + join += this._leftJoinOn[i].toString(false); + } + } + + let where = ''; + if (this._where.length > 0) { + where = ` WHERE ${this._where[0]}`; + for (let i = 1; i < this._where.length; i++) { + where += this._where[i].toString(false); + } + } + + let limit = ''; + if (typeof this._limit === 'number') { + limit = ` LIMIT ${this._limit}`; + if (typeof this._offset === 'number' && this._offset !== 0) { + limit += ` OFFSET ${this._offset}`; + } + } + + let orderBy = ''; + if (typeof this._sortBy === 'string') { + orderBy = ` ORDER BY ${this._sortBy} ${this._sortDirection}`; + } + + const table = `\`${this.table}\``; + + switch (this.type) { + case QueryType.SELECT: + if (this._recursiveRelation) { + const cteFields = fields.replace(RegExp(`${table}`, 'g'), 'o'); + const idKey = this._reverseRecursiveRelation ? + this._recursiveRelation.foreignKey : + this._recursiveRelation.localKey; + const sortOrder = this._reverseRecursiveRelation ? 'DESC' : 'ASC'; + + query = `WITH RECURSIVE cte AS (` + + `SELECT ${fields},1 AS __depth, CONCAT(\`${idKey}\`) AS __path FROM ${table}${where}` + + ` UNION ` + + `SELECT ${cteFields},c.__depth + 1,CONCAT(c.__path,'/',o.\`${idKey}\`) AS __path FROM ${table} AS o, cte AS c WHERE o.\`${this._recursiveRelation.foreignKey}\`=c.\`${this._recursiveRelation.localKey}\`` + + `) SELECT * FROM cte${join}${orderBy || ` ORDER BY __path ${sortOrder}`}${limit}`; + } else { + query = `SELECT ${fields} FROM ${table}${join}${where}${orderBy}${limit}`; + } + + if (this._union) { + const unionOrderBy = this._union.sortBy ? ` ORDER BY ${this._union.sortBy} ${this._union.direction}` : ''; + const unionLimit = typeof this._union.limit === 'number' ? ` LIMIT ${this._union.limit}` : ''; + const unionOffset = typeof this._union.offset === 'number' ? ` OFFSET ${this._union.offset}` : ''; + query = `(${query}) UNION ${this._union.query.toString(false)}${unionOrderBy}${unionLimit}${unionOffset}`; + } + break; + case QueryType.INSERT: { + const insertFields = this.fields.filter(f => f instanceof FieldValue) + .map(f => f as FieldValue); + const insertFieldNames = insertFields.map(f => f.fieldName).join(','); + const insertFieldValues = insertFields.map(f => f.fieldValue).join(','); + query = `INSERT INTO ${table} (${insertFieldNames}) VALUES(${insertFieldValues})`; + break; + } + case QueryType.UPDATE: + query = `UPDATE ${table} SET ${fields}${where}${orderBy}${limit}`; + break; + case QueryType.DELETE: + query = `DELETE FROM ${table}${where}${orderBy}${limit}`; + break; + + } + + return final ? query : `(${query})`; + } + + public build(): string { + return this.toString(true); + } + + public get variables(): QueryVariable[] { + const variables: QueryVariable[] = []; + this.fields.filter(v => v instanceof FieldValue) + .flatMap(v => (v as FieldValue).variables) + .forEach(v => variables.push(v)); + this._where.flatMap(v => this.getVariables(v)) + .forEach(v => variables.push(v)); + this._union?.query.variables.forEach(v => variables.push(v)); + return variables; + } + + private getVariables(where: WhereFieldValue | WhereFieldValueGroup): QueryVariable[] { + return where instanceof WhereFieldValueGroup ? + where.fields.flatMap(v => this.getVariables(v)) : + where.variables; + } + + public async execute(connection?: Connection): Promise { + return await query(this.build(), this.variables, connection); + } + + public async get(connection?: Connection): Promise> { + const queryResult = await this.execute(connection); + const models: ModelQueryResult = []; + models.originalData = []; + + if (this._pivot) models.pivot = []; + + // Eager loading init + const relationMap: { [p: string]: ModelRelation[] } = {}; + for (const relation of this.relations) { + relationMap[relation] = []; + } + + for (const result of queryResult.results) { + const modelData: Record = {}; + for (const field of Object.keys(result)) { + modelData[field.split('.')[1] || field] = result[field]; + } + + const model = this.factory.create(modelData as Pick, false); + models.push(model); + models.originalData.push(modelData); + + if (this._pivot && models.pivot) { + const pivotData: Record = {}; + for (const field of this._pivot) { + pivotData[field] = result[field.split('.')[1]]; + } + models.pivot.push(pivotData); + } + + // Eager loading init map + for (const relation of this.relations) { + if (model[relation] === undefined) throw new Error(`Relation ${relation} doesn't exist on ${model.constructor.name}.`); + if (!(model[relation] instanceof ModelRelation)) throw new Error(`Field ${relation} is not a relation on ${model.constructor.name}.`); + relationMap[relation].push(model[relation] as ModelRelation); + } + } + + // Eager loading execute + for (const relationName of this.relations) { + const relations = relationMap[relationName]; + if (relations.length > 0) { + const allModels = await relations[0].eagerLoad(relations, this.subRelations[relationName]); + await Promise.all(relations.map(r => r.populate(allModels))); + } + } + + return models; + } + + public async paginate(page: number, perPage: number, connection?: Connection): Promise> { + this.limit(perPage, (page - 1) * perPage); + const result = await this.get(connection); + result.pagination = new Pagination(result, page, perPage, await this.count(true, connection)); + return result; + } + + public async first(): Promise { + const models = await this.limit(1).get(); + return models.length > 0 ? models[0] : null; + } + + public async count(removeLimit: boolean = false, connection?: Connection): Promise { + if (removeLimit) { + this._limit = undefined; + this._offset = undefined; + } + this._sortBy = undefined; + this._sortDirection = undefined; + + this.fields.splice(0, this.fields.length); + this.fields.push(new SelectFieldValue('_count', 'COUNT(*)', true)); + + const queryResult = await this.execute(connection); + return Number(queryResult.results[0]['_count']); + } +} + +function inputToFieldOrValue(input: string, addTable?: string): string { + if (input.startsWith('`') || input.startsWith('"') || input.startsWith("'")) { + return input; + } + + let parts = input.split('.'); + if (addTable && parts.length === 1) parts = [addTable, input]; // Add table disambiguation + + return parts.map(v => v === '*' ? v : `\`${v}\``).join('.'); +} + +export interface ModelQueryResult extends Array { + originalData?: Record[]; + pagination?: Pagination; + pivot?: Record[]; +} + +export enum QueryType { + SELECT, + INSERT, + UPDATE, + DELETE, +} + +export enum WhereOperator { + AND = 'AND', + OR = 'OR', +} + +export enum WhereTest { + EQ = '=', + NE = '!=', + GT = '>', + GE = '>=', + LT = '<', + LE = '<=', + IN = ' IN ', +} + +class FieldValue { + protected readonly field: string; + protected value: ModelFieldData; + protected raw: boolean; + + public constructor(field: string, value: ModelFieldData, raw: boolean) { + this.field = field; + this.value = value; + this.raw = raw; + } + + public toString(first: boolean = true): string { + return `${first ? '' : ','}${this.fieldName}${this.test}${this.fieldValue}`; + } + + protected get test(): string { + return '='; + } + + public get variables(): QueryVariable[] { + if (this.value instanceof ModelQuery) return this.value.variables; + if (this.raw || this.value === null || this.value === undefined || + typeof this.value === 'boolean') return []; + if (Array.isArray(this.value)) return this.value.map(value => { + if (!isQueryVariable(value)) value = value.toString(); + return value; + }) as QueryVariable[]; + + let value = this.value; + if (!isQueryVariable(value)) value = value.toString(); + return [value as QueryVariable]; + } + + public get fieldName(): string { + return inputToFieldOrValue(this.field); + } + + public get fieldValue(): ModelFieldData { + let value: string; + if (this.value instanceof ModelQuery) { + value = this.value.toString(false); + } else if (this.value === null || this.value === undefined) { + value = 'null'; + } else if (typeof this.value === 'boolean') { + value = String(this.value); + } else if (this.raw) { + value = this.value.toString(); + } else { + value = Array.isArray(this.value) ? + `(${'?'.repeat(this.value.length).split('').join(',')})` : + '?'; + } + return value; + } +} + +export class SelectFieldValue extends FieldValue { + public toString(): string { + let value: string; + if (this.value instanceof ModelQuery) { + value = this.value.toString(true); + } else if (this.value === null || this.value === undefined) { + value = 'null'; + } else if (typeof this.value === 'boolean') { + value = String(this.value); + } else { + value = this.raw ? + this.value.toString() : + '?'; + } + return `(${value}) AS \`${this.field}\``; + } +} + +class WhereFieldValue extends FieldValue { + private readonly _test: WhereTest; + private readonly operator: WhereOperator; + + public constructor(field: string, value: ModelFieldData, raw: boolean, test: WhereTest, operator: WhereOperator) { + super(field, value, raw); + this._test = test; + this.operator = operator; + } + + public toString(first: boolean = true): string { + return (!first ? ` ${this.operator} ` : '') + super.toString(true); + } + + protected get test(): string { + if (this.value === null || this.value === undefined) { + if (this._test === WhereTest.EQ) { + return ' IS '; + } else if (this._test === WhereTest.NE) { + return ' IS NOT '; + } + } + return this._test; + } +} + +class WhereFieldValueGroup { + public readonly fields: (WhereFieldValue | WhereFieldValueGroup)[]; + public readonly operator: WhereOperator; + + public constructor(fields: (WhereFieldValue | WhereFieldValueGroup)[], operator: WhereOperator) { + this.fields = fields; + this.operator = operator; + } + + public toString(first: boolean = true): string { + let str = `${first ? '' : ` ${this.operator} `}(`; + let firstField = true; + for (const field of this.fields) { + str += field.toString(firstField); + firstField = false; + } + str += ')'; + return str; + } +} + +export interface WhereFieldConsumer { + where(field: string, value: ModelFieldData, test?: WhereTest, operator?: WhereOperator): this; + + groupWhere(setter: (query: WhereFieldConsumer) => void, operator?: WhereOperator): this; +} + +export type QueryFields = (string | SelectFieldValue | FieldValue)[]; + +export type SortDirection = 'ASC' | 'DESC'; + +type ModelQueryUnion = { + query: ModelQuery, + sortBy: string, + direction: SortDirection, + limit?: number, + offset?: number, +}; + +export type ModelFieldData = + | QueryVariable + | ModelQuery + | { toString(): string } + | (QueryVariable | { toString(): string })[]; diff --git a/src/db/ModelRelation.ts b/src/db/ModelRelation.ts new file mode 100644 index 0000000..1142995 --- /dev/null +++ b/src/db/ModelRelation.ts @@ -0,0 +1,268 @@ +import ModelQuery, {ModelFieldData, ModelQueryResult, WhereTest} from "./ModelQuery"; +import Model, {ModelType} from "./Model"; +import ModelFactory from "./ModelFactory"; + +export default abstract class ModelRelation { + protected readonly model: S; + protected readonly foreignModelType: ModelType; + protected readonly dbProperties: RelationDatabaseProperties; + protected readonly queryModifiers: QueryModifier[] = []; + protected readonly filters: ModelFilter[] = []; + protected cachedModels?: O[]; + + protected constructor(model: S, foreignModelType: ModelType, dbProperties: RelationDatabaseProperties) { + this.model = model; + this.foreignModelType = foreignModelType; + this.dbProperties = dbProperties; + } + + public abstract clone(): ModelRelation; + + public constraint(queryModifier: QueryModifier): this { + this.queryModifiers.push(queryModifier); + return this; + } + + public filter(modelFilter: ModelFilter): this { + this.filters.push(modelFilter); + return this; + } + + protected makeQuery(): ModelQuery { + const query = ModelFactory.get(this.foreignModelType).select(); + for (const modifier of this.queryModifiers) modifier(query); + return query; + } + + public getModelId(): ModelFieldData { + return this.model[this.dbProperties.localKey]; + } + + protected applyRegularConstraints(query: ModelQuery): void { + query.where(this.dbProperties.foreignKey, this.getModelId()); + } + + public async get(): Promise { + if (this.cachedModels === undefined) { + const query = this.makeQuery(); + this.applyRegularConstraints(query); + this.cachedModels = await query.get(); + } + + let models = this.cachedModels; + for (const filter of this.filters) { + const newModels = []; + for (const model of models) { + if (await filter(model)) { + newModels.push(model); + } + } + models = newModels; + } + return this.collectionToOutput(models); + } + + public getOrFail(): R { + if (this.cachedModels === undefined) throw new Error('Models were not fetched'); + return this.collectionToOutput(this.cachedModels); + } + + protected abstract collectionToOutput(models: O[]): R; + + public async eagerLoad( + relations: ModelRelation[], + subRelations: string[] = [], + ): Promise> { + const ids = relations.map(r => r.getModelId()) + .filter(id => id !== null && id !== undefined) + .reduce((array: ModelFieldData[], val) => array.indexOf(val) >= 0 ? array : [...array, val], []); + if (ids.length === 0) return []; + + const query = this.makeQuery(); + query.where(this.dbProperties.foreignKey, ids, WhereTest.IN); + query.with(...subRelations); + return await query.get(); + } + + public async populate(models: ModelQueryResult): Promise { + this.cachedModels = models.filter(m => m[this.dbProperties.foreignKey] === this.getModelId()) + .reduce((array: O[], val) => array.find(v => v.equals(val)) ? array : [...array, val], []); + } + + public async count(): Promise { + const models = await this.get(); + if (Array.isArray(models)) return models.length; + else return models !== null ? 1 : 0; + } + + public async has(model: O): Promise { + const models = await this.get(); + if (models instanceof Array) { + return models.find(m => m.equals(model)) !== undefined; + } else { + return models !== null && models.equals(model); + } + } +} + +export class OneModelRelation extends ModelRelation { + public constructor(model: S, foreignModelType: ModelType, dbProperties: RelationDatabaseProperties) { + super(model, foreignModelType, dbProperties); + } + + public clone(): OneModelRelation { + return new OneModelRelation(this.model, this.foreignModelType, this.dbProperties); + } + + protected collectionToOutput(models: O[]): O | null { + return models[0] || null; + } + + public async set(model: O): Promise { + (this.model as Model)[this.dbProperties.localKey] = model[this.dbProperties.foreignKey]; + } + + public async clear(): Promise { + (this.model as Model)[this.dbProperties.localKey] = undefined; + } +} + +export class ManyModelRelation extends ModelRelation { + protected readonly paginatedCache: { + [perPage: number]: { + [pageNumber: number]: ModelQueryResult | undefined + } | undefined + } = {}; + + public constructor(model: S, foreignModelType: ModelType, dbProperties: RelationDatabaseProperties) { + super(model, foreignModelType, dbProperties); + } + + public clone(): ManyModelRelation { + return new ManyModelRelation(this.model, this.foreignModelType, this.dbProperties); + } + + public cloneReduceToOne(): OneModelRelation { + return new OneModelRelation(this.model, this.foreignModelType, this.dbProperties); + } + + protected collectionToOutput(models: O[]): O[] { + return models; + } + + public async paginate(page: number, perPage: number): Promise> { + let cache = this.paginatedCache[perPage]; + if (!cache) cache = this.paginatedCache[perPage] = {}; + + let cachePage = cache[page]; + if (!cachePage) { + const query = this.makeQuery(); + this.applyRegularConstraints(query); + cachePage = cache[page] = await query.paginate(page, perPage); + } + + return cachePage; + } +} + +export class ManyThroughModelRelation extends ManyModelRelation { + protected readonly dbProperties: PivotRelationDatabaseProperties; + + public constructor(model: S, foreignModelType: ModelType, dbProperties: PivotRelationDatabaseProperties) { + super(model, foreignModelType, dbProperties); + this.dbProperties = dbProperties; + this.constraint(query => query + .leftJoin(this.dbProperties.pivotTable, 'pivot') + .on(`pivot.${this.dbProperties.foreignPivotKey}`, `${this.foreignModelType.table}.${this.dbProperties.foreignKey}`), + ); + } + + public clone(): ManyThroughModelRelation { + return new ManyThroughModelRelation(this.model, this.foreignModelType, this.dbProperties); + } + + public cloneReduceToOne(): OneModelRelation { + throw new Error('Cannot reduce many through relation to one model.'); + } + + protected applyRegularConstraints(query: ModelQuery): void { + query.where(`pivot.${this.dbProperties.localPivotKey}`, this.getModelId()); + } + + public async eagerLoad( + relations: ModelRelation[], + subRelations: string[] = [], + ): Promise> { + const ids = relations.map(r => r.getModelId()) + .reduce((array: ModelFieldData[], val) => array.indexOf(val) >= 0 ? array : [...array, val], []); + if (ids.length === 0) return []; + + const query = this.makeQuery(); + query.where(`pivot.${this.dbProperties.localPivotKey}`, ids, WhereTest.IN); + query.pivot(`pivot.${this.dbProperties.localPivotKey}`, `pivot.${this.dbProperties.foreignPivotKey}`); + query.with(...subRelations); + return await query.get(); + } + + public async populate(models: ModelQueryResult): Promise { + if (!models.pivot) throw new Error('ModelQueryResult.pivot not loaded.'); + const ids = models.pivot + .filter(p => p[`pivot.${this.dbProperties.localPivotKey}`] === this.getModelId()) + .map(p => p[`pivot.${this.dbProperties.foreignPivotKey}`]); + this.cachedModels = models.filter(m => ids.indexOf(m[this.dbProperties.foreignKey]) >= 0) + .reduce((array: O[], val) => array.find(v => v.equals(val)) ? array : [...array, val], []); + } +} + +export class RecursiveModelRelation extends ManyModelRelation { + private readonly reverse: boolean; + + public constructor( + model: M, + foreignModelType: ModelType, + dbProperties: RelationDatabaseProperties, + reverse: boolean = false, + ) { + super(model, foreignModelType, dbProperties); + this.constraint(query => query.recursive(this.dbProperties, reverse)); + this.reverse = reverse; + } + + public clone(): RecursiveModelRelation { + return new RecursiveModelRelation(this.model, this.foreignModelType, this.dbProperties); + } + + public async populate(models: ModelQueryResult): Promise { + await super.populate(models); + const cachedModels = this.cachedModels; + if (cachedModels) { + let count; + do { + count = cachedModels.length; + cachedModels.push(...models.filter(model => + !cachedModels.find(cached => cached.equals(model)) && cachedModels.find(cached => { + return cached[this.dbProperties.localKey] === model[this.dbProperties.foreignKey]; + }), + ).reduce((array: M[], val) => array.find(v => v.equals(val)) ? array : [...array, val], [])); + } while (count !== cachedModels.length); + + if (this.reverse) cachedModels.reverse(); + } + } + +} + +export type QueryModifier = (query: ModelQuery) => ModelQuery; + +export type ModelFilter = (model: O) => boolean | Promise; + +export type RelationDatabaseProperties = { + localKey: string; + foreignKey: string; +}; + +export type PivotRelationDatabaseProperties = RelationDatabaseProperties & { + pivotTable: string; + localPivotKey: string; + foreignPivotKey: string; +}; diff --git a/src/db/MysqlConnectionManager.ts b/src/db/MysqlConnectionManager.ts index c991309..cc8600d 100644 --- a/src/db/MysqlConnectionManager.ts +++ b/src/db/MysqlConnectionManager.ts @@ -1,17 +1,21 @@ -import mysql, {Connection, FieldInfo, Pool} from 'mysql'; +import mysql, {Connection, FieldInfo, MysqlError, Pool, PoolConnection} from 'mysql'; import config from 'config'; -import Migration from "./Migration"; -import Logger from "../Logger"; +import Migration, {MigrationType} from "./Migration"; +import {logger} from "../Logger"; import {Type} from "../Utils"; export interface QueryResult { - readonly results: any[]; + readonly results: Record[]; readonly fields: FieldInfo[]; - readonly other?: any; + readonly other?: Record; foundRows?: number; } -export async function query(queryString: string, values?: any, connection?: Connection): Promise { +export async function query( + queryString: string, + values?: QueryVariable[], + connection?: Connection, +): Promise { return await MysqlConnectionManager.query(queryString, values, connection); } @@ -21,7 +25,11 @@ export default class MysqlConnectionManager { private static migrationsRegistered: boolean = false; private static readonly migrations: Migration[] = []; - public static registerMigrations(migrations: Type[]) { + public static isReady(): boolean { + return this.databaseReady && this.currentPool !== undefined; + } + + public static registerMigrations(migrations: MigrationType[]): void { if (!this.migrationsRegistered) { this.migrationsRegistered = true; migrations.forEach(m => this.registerMigration(v => new m(v))); @@ -32,30 +40,36 @@ export default class MysqlConnectionManager { this.migrations.push(migration(this.migrations.length + 1)); } - public static async prepare() { + public static hasMigration(migration: Type): boolean { + for (const m of this.migrations) { + if (m.constructor === migration) return true; + } + return false; + } + + public static async prepare(runMigrations: boolean = true): Promise { if (config.get('mysql.create_database_automatically') === true) { const dbName = config.get('mysql.database'); - Logger.info(`Creating database ${dbName}...`); + logger.info(`Creating database ${dbName}...`); const connection = mysql.createConnection({ host: config.get('mysql.host'), user: config.get('mysql.user'), password: config.get('mysql.password'), + charset: 'utf8mb4', }); - await new Promise((resolve, reject) => { + await new Promise((resolve, reject) => { connection.query(`CREATE DATABASE IF NOT EXISTS ${dbName}`, (error) => { - if (error !== null) { - reject(error); - } else { + return error !== null ? + reject(error) : resolve(); - } }); }); connection.end(); - Logger.info(`Database ${dbName} created!`); + logger.info(`Database ${dbName} created!`); } this.databaseReady = true; - await this.handleMigrations(); + if (runMigrations) await this.handleMigrations(); } public static get pool(): Pool { @@ -72,26 +86,34 @@ export default class MysqlConnectionManager { user: config.get('mysql.user'), password: config.get('mysql.password'), database: config.get('mysql.database'), + charset: 'utf8mb4', }); } public static async endPool(): Promise { - return new Promise(resolve => { - if (this.currentPool !== undefined) { - this.currentPool.end(() => { - Logger.info('Mysql connection pool ended.'); - resolve(); - }); - this.currentPool = undefined; - } else { - resolve(); + return await new Promise(resolve => { + if (this.currentPool === undefined) { + return resolve(); } + + this.currentPool.end(() => { + logger.info('Mysql connection pool ended.'); + resolve(); + }); + this.currentPool = undefined; }); } - public static async query(queryString: string, values?: any, connection?: Connection): Promise { + public static async query( + queryString: string, + values: QueryVariable[] = [], + connection?: Connection, + ): Promise { return await new Promise((resolve, reject) => { - Logger.dev('Mysql query:', queryString, '; values:', values); + logger.debug('SQL:', logger.settings.minLevel === 'trace' || logger.settings.minLevel === 'silly' ? + mysql.format(queryString, values) : + queryString); + (connection ? connection : this.pool).query(queryString, values, (error, results, fields) => { if (error !== null) { reject(error); @@ -101,7 +123,7 @@ export default class MysqlConnectionManager { resolve({ results: Array.isArray(results) ? results : [], fields: fields !== undefined ? fields : [], - other: Array.isArray(results) ? null : results + other: Array.isArray(results) ? null : results, }); }); }); @@ -109,70 +131,139 @@ export default class MysqlConnectionManager { public static async wrapTransaction(transaction: (connection: Connection) => Promise): Promise { return await new Promise((resolve, reject) => { - this.pool.getConnection((err, connection) => { + this.pool.getConnection((err: MysqlError | undefined, connection: PoolConnection) => { if (err) { reject(err); return; } - connection.beginTransaction((err) => { + connection.beginTransaction((err?: MysqlError) => { if (err) { reject(err); - this.pool.releaseConnection(connection); + connection.release(); return; } transaction(connection).then(val => { - connection.commit((err) => { + connection.commit((err?: MysqlError) => { if (err) { this.rejectAndRollback(connection, err, reject); - this.pool.releaseConnection(connection); + connection.release(); return; } - this.pool.releaseConnection(connection); + connection.release(); resolve(val); }); }).catch(err => { this.rejectAndRollback(connection, err, reject); - this.pool.releaseConnection(connection); + connection.release(); }); }); }); }); } - private static rejectAndRollback(connection: Connection, err: any, reject: (err: any) => void) { - connection.rollback((rollbackErr) => { - if (rollbackErr) { - reject(err + '\n' + rollbackErr); - } else { + private static rejectAndRollback( + connection: Connection, + err: MysqlError | undefined, + reject: (err: unknown) => void, + ) { + connection.rollback((rollbackErr?: MysqlError) => { + return rollbackErr ? + reject(err + '\n' + rollbackErr) : reject(err); - } }); } - private static async handleMigrations() { + public static async getCurrentMigrationVersion(): Promise { let currentVersion = 0; try { const result = await query('SELECT id FROM migrations ORDER BY id DESC LIMIT 1'); - currentVersion = result.results[0].id; + currentVersion = Number(result.results[0]?.id); } catch (e) { if (e.code === 'ECONNREFUSED' || e.code !== 'ER_NO_SUCH_TABLE') { throw new Error('Cannot run migrations: ' + e.code); } } + return currentVersion; + } + + private static async handleMigrations() { + const currentVersion = await this.getCurrentMigrationVersion(); for (const migration of this.migrations) { if (await migration.shouldRun(currentVersion)) { - Logger.info('Running migration ', migration.version, migration.constructor.name); - await migration.install(); - await query('INSERT INTO migrations VALUES(?, ?, NOW())', [ - migration.version, - migration.constructor.name, - ]); + logger.info('Running migration ', migration.version, migration.constructor.name); + await MysqlConnectionManager.wrapTransaction(async c => { + migration.setCurrentConnection(c); + await migration.install(); + migration.setCurrentConnection(null); + await query('INSERT INTO migrations VALUES(?, ?, NOW())', [ + migration.version, + migration.constructor.name, + ]); + }); } } + + for (const migration of this.migrations) { + migration.registerModels?.(); + } } -} \ No newline at end of file + + /** + * @param migrationId what migration to rollback. Use with caution. default=0 is for last registered migration. + */ + public static async rollbackMigration(migrationId: number = 0): Promise { + migrationId--; + const migration = this.migrations[migrationId]; + logger.info('Rolling back migration ', migration.version, migration.constructor.name); + await MysqlConnectionManager.wrapTransaction(async c => { + migration.setCurrentConnection(c); + await migration.rollback(); + migration.setCurrentConnection(null); + await query('DELETE FROM migrations WHERE id=?', [migration.version]); + }); + } + + public static async migrationCommand(args: string[]): Promise { + try { + logger.info('Current migration:', await this.getCurrentMigrationVersion()); + + for (let i = 0; i < args.length; i++) { + if (args[i] === 'rollback') { + let migrationId = 0; + if (args.length > i + 1) { + migrationId = parseInt(args[i + 1]); + } + await this.prepare(false); + await this.rollbackMigration(migrationId); + return; + } + } + } finally { + await MysqlConnectionManager.endPool(); + } + } +} + +export type QueryVariable = + | boolean + | string + | number + | Date + | Buffer + | null + | undefined; + +export function isQueryVariable(value: unknown): value is QueryVariable { + return typeof value === 'boolean' || + typeof value === "string" || + typeof value === 'number' || + value instanceof Date || + value instanceof Buffer || + value === null || + value === undefined; +} diff --git a/src/db/Query.ts b/src/db/Query.ts deleted file mode 100644 index 882f5eb..0000000 --- a/src/db/Query.ts +++ /dev/null @@ -1,214 +0,0 @@ -import {query, QueryResult} from "./MysqlConnectionManager"; -import {Connection} from "mysql"; - -export default class Query { - public static select(table: string, ...fields: string[]): Query { - return new Query(QueryType.SELECT, table, fields.length > 0 ? fields : ['*']); - } - - public static update(table: string, data: { - [key: string]: any - }) { - const fields = []; - for (let key in data) { - if (data.hasOwnProperty(key)) { - fields.push(new UpdateFieldValue(key, data[key])); - } - } - return new Query(QueryType.UPDATE, table, fields); - } - - public static delete(table: string) { - return new Query(QueryType.DELETE, table); - } - - private readonly type: QueryType; - private readonly table: string; - private readonly fields: (string | SelectFieldValue | UpdateFieldValue)[]; - private _where: WhereFieldValue[] = []; - private _limit?: number; - private _offset?: number; - private _sortBy?: string; - private _sortDirection?: 'ASC' | 'DESC'; - private _foundRows: boolean = false; - - private constructor(type: QueryType, table: string, fields?: (string | SelectFieldValue | UpdateFieldValue)[]) { - this.type = type; - this.table = table; - this.fields = fields || []; - } - - public where(field: string, value: string | Date | Query | any, operator: WhereOperator = WhereOperator.AND, test: WhereTest = WhereTest.EQUALS): Query { - this._where.push(new WhereFieldValue(field, value, operator, test)); - return this; - } - - public whereNot(field: string, value: string | Date | Query | any, operator: WhereOperator = WhereOperator.AND): Query { - return this.where(field, value, operator, WhereTest.DIFFERENT); - } - - public orWhere(field: string, value: string | Date | Query | any): Query { - return this.where(field, value, WhereOperator.OR); - } - - public whereIn(field: string, value: any[]): Query { - return this.where(field, value, WhereOperator.AND, WhereTest.IN); - } - - public limit(limit: number, offset: number = 0): Query { - this._limit = limit; - this._offset = offset; - return this; - } - - public first(): Query { - return this.limit(1); - } - - public sortBy(field: string, direction: 'ASC' | 'DESC' = 'ASC'): Query { - this._sortBy = field; - this._sortDirection = direction; - return this; - } - - public withTotalRowCount(): Query { - this._foundRows = true; - return this; - } - - public toString(final: boolean = false): string { - let query = ''; - - let fields = this.fields?.join(','); - - let where = ''; - if (this._where.length > 0) { - where = `WHERE ${this._where[0]}`; - for (let i = 1; i < this._where.length; i++) { - where += this._where[i].toString(false); - } - } - - let limit = ''; - if (typeof this._limit === 'number') { - limit = `LIMIT ${this._limit}`; - if (typeof this._offset === 'number' && this._offset !== 0) { - limit += ` OFFSET ${this._offset}`; - } - } - - let orderBy = ''; - if (typeof this._sortBy === 'string') { - orderBy = `ORDER BY ${this._sortBy} ${this._sortDirection}`; - } - - switch (this.type) { - case QueryType.SELECT: - query = `SELECT ${this._foundRows ? 'SQL_CALC_FOUND_ROWS' : ''} ${fields} FROM ${this.table} ${where} ${orderBy} ${limit}`; - break; - case QueryType.UPDATE: - query = `UPDATE ${this.table} SET ${fields} ${where} ${orderBy} ${limit}`; - break; - case QueryType.DELETE: - query = `DELETE FROM ${this.table} ${where} ${orderBy} ${limit}`; - break; - - } - - return final ? query : `(${query})`; - } - - public build(): string { - return this.toString(true); - } - - public get variables(): any[] { - const variables: any[] = []; - this.fields?.filter(v => v instanceof FieldValue) - .flatMap(v => (v).variables) - .forEach(v => variables.push(v)); - this._where.flatMap(v => v.variables) - .forEach(v => variables.push(v)); - return variables; - } - - public isCacheable(): boolean { - return this.type === QueryType.SELECT && this.fields.length === 1 && this.fields[0] === '*'; - } - - public async execute(connection?: Connection): Promise { - const queryResult = await query(this.build(), this.variables, connection); - if (this._foundRows) { - const foundRows = await query('SELECT FOUND_ROWS() as r', undefined, connection); - queryResult.foundRows = foundRows.results[0].r; - } - return queryResult; - } -} - -export enum QueryType { - SELECT, - UPDATE, - DELETE, -} - -enum WhereOperator { - AND = 'AND', - OR = 'OR', -} - -enum WhereTest { - EQUALS = '=', - DIFFERENT = '!=', - IN = ' IN ', -} - -class FieldValue { - protected readonly field: string; - protected value: any; - - constructor(field: string, value: any) { - this.field = field; - this.value = value; - } - - public toString(first: boolean = true): string { - return `${!first ? ',' : ''}${this.field}${this.test}${this.value instanceof Query ? this.value : (Array.isArray(this.value) ? '(?)' : '?')}`; - } - - protected get test(): string { - return '='; - } - - public get variables(): any[] { - return this.value instanceof Query ? this.value.variables : [this.value]; - } -} - -class SelectFieldValue extends FieldValue { - public toString(first: boolean = true): string { - return `(${this.value instanceof Query ? this.value : '?'}) AS ${this.field}`; - } -} - -class UpdateFieldValue extends FieldValue { -} - -class WhereFieldValue extends FieldValue { - private readonly operator: WhereOperator; - private readonly _test: WhereTest; - - constructor(field: string, value: any, operator: WhereOperator, test: WhereTest) { - super(field, value); - this.operator = operator; - this._test = test; - } - - public toString(first: boolean = true): string { - return (!first ? ` ${this.operator} ` : '') + super.toString(true); - } - - protected get test(): string { - return this._test; - } -} \ No newline at end of file diff --git a/src/db/Validator.ts b/src/db/Validator.ts index e76ed9a..9440456 100644 --- a/src/db/Validator.ts +++ b/src/db/Validator.ts @@ -1,32 +1,76 @@ -import Model from "./Model"; -import Query from "./Query"; +import Model, {ModelType} from "./Model"; +import ModelQuery, {WhereTest} from "./ModelQuery"; import {Connection} from "mysql"; +import {ServerError} from "../HttpError"; -export default class Validator { - private readonly steps: ValidationStep[] = []; +export const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/; + +export default class Validator { + public static async validate( + validationMap: { [p: string]: Validator }, + body: { [p: string]: unknown }, + ): Promise { + const bag = new ValidationBag(); + + for (const p of Object.keys(validationMap)) { + try { + await validationMap[p].execute(p, body[p], false); + } catch (e) { + if (e instanceof ValidationBag) { + bag.addBag(e); + } else throw e; + } + } + + if (bag.hasMessages()) throw bag; + } + + + private readonly steps: ValidationStep[] = []; private readonly validationAttributes: string[] = []; + private readonly rawValueToHuman?: (val: V) => string; private _min?: number; private _max?: number; + public constructor(rawValueToHuman?: (val: V) => string) { + this.rawValueToHuman = rawValueToHuman; + } + /** * @param thingName The name of the thing to validate. * @param value The value to verify. * @param onlyFormat {@code true} to only validate format properties, {@code false} otherwise. * @param connection A connection to use in case of wrapped transactions. */ - async execute(thingName: string, value: T | undefined, onlyFormat: boolean, connection?: Connection): Promise { - const bag = new ValidationBag(); + public async execute( + thingName: string, + value: V | undefined, + onlyFormat: boolean, + connection?: Connection, + ): Promise { + const bag = new ValidationBag(); for (const step of this.steps) { if (onlyFormat && !step.isFormat) continue; - const result = step.verifyStep(value, thingName, connection); - if ((result === false || result instanceof Promise && (await result) === false) && step.throw) { - const error: ValidationError = step.throw(); + let result; + try { + result = step.verifyStep(value, thingName, connection); + if (result instanceof Promise) { + result = await result; + } + } catch (e) { + throw new ServerError(`An error occurred while validating ${thingName} with value "${value}".`, e); + } + + if (result === false && step.throw) { + const error: ValidationError = step.throw(); + error.rawValueToHuman = this.rawValueToHuman; error.thingName = thingName; error.value = value; bag.addMessage(error); + break; } else if (step.interrupt !== undefined && step.interrupt(value)) { break; } @@ -37,7 +81,7 @@ export default class Validator { } } - public defined(): Validator { + public defined(): Validator { this.validationAttributes.push('required'); this.addStep({ @@ -48,17 +92,21 @@ export default class Validator { return this; } - public acceptUndefined(): Validator { + public acceptUndefined(alsoAcceptEmptyString: boolean = false): Validator { this.addStep({ verifyStep: () => true, throw: null, - interrupt: val => val === undefined || val === null, + interrupt: val => { + return val === undefined || + val === null || + alsoAcceptEmptyString && typeof val === 'string' && val.length === 0; + }, isFormat: true, }); return this; } - public equals(other?: T): Validator { + public equals(other?: V): Validator { this.addStep({ verifyStep: val => val === other, throw: () => new BadValueValidationError(other), @@ -67,7 +115,16 @@ export default class Validator { return this; } - public regexp(regexp: RegExp): Validator { + public sameAs(otherName?: string, other?: V): Validator { + this.addStep({ + verifyStep: val => val === other, + throw: () => new DifferentThanError(otherName), + isFormat: true, + }); + return this; + } + + public regexp(regexp: RegExp): Validator { this.validationAttributes.push(`pattern="${regexp}"`); this.addStep({ verifyStep: val => regexp.test(val), @@ -77,24 +134,48 @@ export default class Validator { return this; } - public length(length: number): Validator { + public length(length: number): Validator { this.addStep({ - verifyStep: val => (val).length === length, + verifyStep: val => isLenghtable(val) && val.length === length, throw: () => new BadLengthValidationError(length), isFormat: true, }); return this; } + /** + * @param minLength included + */ + public minLength(minLength: number): Validator { + this.addStep({ + verifyStep: val => isLenghtable(val) && val.length >= minLength, + throw: () => new TooShortError(minLength), + isFormat: true, + }); + return this; + } + + /** + * @param maxLength included + */ + public maxLength(maxLength: number): Validator { + this.addStep({ + verifyStep: val => isLenghtable(val) && val.length <= maxLength, + throw: () => new TooLongError(maxLength), + isFormat: true, + }); + return this; + } + /** * @param minLength included * @param maxLength included */ - public between(minLength: number, maxLength: number): Validator { + public between(minLength: number, maxLength: number): Validator { this.addStep({ verifyStep: val => { - const length = (val).length; - return length >= minLength && length <= maxLength; + return isLenghtable(val) && + val.length >= minLength && val.length <= maxLength; }, throw: () => new BadLengthValidationError(minLength, maxLength), isFormat: true, @@ -105,12 +186,12 @@ export default class Validator { /** * @param min included */ - public min(min: number): Validator { + public min(min: number): Validator { this.validationAttributes.push(`min="${min}"`); this._min = min; this.addStep({ verifyStep: val => { - return (val) >= min; + return typeof val === 'number' && val >= min; }, throw: () => new OutOfRangeValidationError(this._min, this._max), isFormat: true, @@ -121,12 +202,12 @@ export default class Validator { /** * @param max included */ - public max(max: number): Validator { + public max(max: number): Validator { this.validationAttributes.push(`max="${max}"`); this._max = max; this.addStep({ verifyStep: val => { - return (val) <= max; + return typeof val === 'number' && val <= max; }, throw: () => new OutOfRangeValidationError(this._min, this._max), isFormat: true, @@ -134,16 +215,23 @@ export default class Validator { return this; } - public unique(model: Model, querySupplier?: () => Query): Validator { + public unique( + model: M | ModelType, + foreignKey?: string, + querySupplier?: () => ModelQuery, + ): Validator { this.addStep({ verifyStep: async (val, thingName, c) => { - let query: Query; + if (!foreignKey) foreignKey = thingName; + let query: ModelQuery; if (querySupplier) { - query = querySupplier().where(thingName, val); + query = querySupplier(); } else { - query = (model.constructor).select('1').where(thingName, val); + query = (model instanceof Model ? >model.constructor : model).select(''); } - if (typeof model.id === 'number') query = query.whereNot('id', model.id); + query.where(foreignKey, val); + if (model instanceof Model && typeof model.id === 'number') + query = query.where('id', model.id, WhereTest.NE); return (await query.execute(c)).results.length === 0; }, throw: () => new AlreadyExistsValidationError(model.table), @@ -152,16 +240,21 @@ export default class Validator { return this; } - public exists(modelClass: Function, foreignKey?: string): Validator { + public exists(modelType: ModelType, foreignKey?: string): Validator { this.addStep({ - verifyStep: async (val, thingName, c) => (await (modelClass).select('1').where(foreignKey !== undefined ? foreignKey : thingName, val).execute(c)).results.length >= 1, - throw: () => new UnknownRelationValidationError((modelClass).table, foreignKey), + verifyStep: async (val, thingName, c) => { + const results = await modelType.select('') + .where(foreignKey !== undefined ? foreignKey : thingName, val) + .execute(c); + return results.results.length >= 1; + }, + throw: () => new UnknownRelationValidationError(modelType.table, foreignKey), isFormat: false, }); return this; } - private addStep(step: ValidationStep) { + private addStep(step: ValidationStep) { this.steps.push(step); } @@ -169,60 +262,72 @@ export default class Validator { return this.validationAttributes; } - public step(step: number): Validator { + public step(step: number): Validator { this.validationAttributes.push(`step="${step}"`); return this; } } -interface ValidationStep { - interrupt?: (val?: T) => boolean; +interface ValidationStep { + interrupt?: (val?: V) => boolean; - verifyStep(val: T | undefined, thingName: string, connection?: Connection): boolean | Promise; + verifyStep(val: V | undefined, thingName: string, connection?: Connection): boolean | Promise; - throw: ((val?: T) => ValidationError) | null; + throw: ((val?: V) => ValidationError) | null; readonly isFormat: boolean; } -export class ValidationBag extends Error { - private readonly messages: { [p: string]: any } = {}; +export class ValidationBag extends Error { + private readonly errors: ValidationError[] = []; - public addMessage(err: ValidationError) { - if (!err.thingName) { - throw new Error('Null thing name'); + public addMessage(err: ValidationError): void { + if (!err.thingName) throw new Error('Null thing name'); + this.errors.push(err); + } + + public addBag(otherBag: ValidationBag): void { + for (const error of otherBag.errors) { + this.errors.push(error); } - - this.messages[err.thingName] = { - name: err.name, - message: err.message, - value: err.value, - }; } public hasMessages(): boolean { - return Object.keys(this.messages).length > 0; + return this.errors.length > 0; } - public getMessages(): { [p: string]: ValidationError } { - return this.messages; + public getMessages(): { [p: string]: ValidationError } { + const messages: { [p: string]: ValidationError } = {}; + for (const err of this.errors) { + messages[err.thingName || 'unknown'] = { + name: err.name, + message: err.message, + value: err.value, + }; + } + return messages; + } + + public getErrors(): ValidationError[] { + return this.errors; } } -export abstract class ValidationError extends Error { +export class ValidationError extends Error { + public rawValueToHuman?: (val: V) => string; public thingName?: string; - public value?: any; + public value?: V; public get name(): string { return this.constructor.name; } } -export class BadLengthValidationError extends ValidationError { +export class BadLengthValidationError extends ValidationError { private readonly expectedLength: number; private readonly maxLength?: number; - constructor(expectedLength: number, maxLength?: number) { + public constructor(expectedLength: number, maxLength?: number) { super(); this.expectedLength = expectedLength; this.maxLength = maxLength; @@ -230,28 +335,73 @@ export class BadLengthValidationError extends ValidationError { public get message(): string { return `${this.thingName} expected length: ${this.expectedLength}${this.maxLength !== undefined ? ` to ${this.maxLength}` : ''}; ` + - `actual length: ${this.value.length}.`; + `actual length: ${isLenghtable(this.value) && this.value.length}.`; } } -export class BadValueValidationError extends ValidationError { - private readonly expectedValue: any; +export class TooShortError extends ValidationError { + private readonly minLength: number; - constructor(expectedValue: any) { + public constructor(minLength: number) { + super(); + this.minLength = minLength; + } + + public get message(): string { + return `${this.thingName} must be at least ${this.minLength} characters.`; + } +} + +export class TooLongError extends ValidationError { + private readonly maxLength: number; + + public constructor(maxLength: number) { + super(); + this.maxLength = maxLength; + } + + public get message(): string { + return `${this.thingName} must be at most ${this.maxLength} characters.`; + } +} + +export class BadValueValidationError extends ValidationError { + private readonly expectedValue: V; + + public constructor(expectedValue: V) { super(); this.expectedValue = expectedValue; } public get message(): string { - return `Expected: ${this.expectedValue}; got: ${this.value}.` + let expectedValue: string = String(this.expectedValue); + let actualValue: string = String(this.value); + if (this.rawValueToHuman && this.value) { + expectedValue = this.rawValueToHuman(this.expectedValue); + actualValue = this.rawValueToHuman(this.value); + } + return `Expected: ${expectedValue}; got: ${actualValue}.`; } } -export class OutOfRangeValidationError extends ValidationError { +export class DifferentThanError extends ValidationError { + private readonly otherName?: string; + + public constructor(otherName?: string) { + super(); + this.otherName = otherName; + } + + public get message(): string { + return `This should be the same as ${this.otherName}.`; + } +} + +export class OutOfRangeValidationError extends ValidationError { private readonly min?: number; private readonly max?: number; - constructor(min?: number, max?: number) { + public constructor(min?: number, max?: number) { super(); this.min = min; this.max = max; @@ -263,40 +413,46 @@ export class OutOfRangeValidationError extends ValidationError { } else if (this.max === undefined) { return `${this.thingName} must be at least ${this.min}`; } - return `${this.thingName} must be between ${this.min} and ${this.max}.`; + let min: string = String(this.min); + let max: string = String(this.max); + if (this.rawValueToHuman) { + min = this.rawValueToHuman(this.min as unknown as V); + max = this.rawValueToHuman(this.max as unknown as V); + } + return `${this.thingName} must be between ${min} and ${max}.`; } } -export class InvalidFormatValidationError extends ValidationError { +export class InvalidFormatValidationError extends ValidationError { public get message(): string { return `"${this.value}" is not a valid ${this.thingName}.`; } } -export class UndefinedValueValidationError extends ValidationError { +export class UndefinedValueValidationError extends ValidationError { public get message(): string { return `${this.thingName} is required.`; } } -export class AlreadyExistsValidationError extends ValidationError { +export class AlreadyExistsValidationError extends ValidationError { private readonly table: string; - constructor(table: string) { + public constructor(table: string) { super(); this.table = table; } public get message(): string { - return `${this.value} already exists in ${this.table}.${this.thingName}.`; + return `${this.thingName} already exists in ${this.table}.`; } } -export class UnknownRelationValidationError extends ValidationError { +export class UnknownRelationValidationError extends ValidationError { private readonly table: string; private readonly foreignKey?: string; - constructor(table: string, foreignKey?: string) { + public constructor(table: string, foreignKey?: string) { super(); this.table = table; this.foreignKey = foreignKey; @@ -305,4 +461,26 @@ export class UnknownRelationValidationError extends ValidationError { public get message(): string { return `${this.thingName}=${this.value} relation was not found in ${this.table}${this.foreignKey !== undefined ? `.${this.foreignKey}` : ''}.`; } -} \ No newline at end of file +} + +export class FileError extends ValidationError { + private readonly _message: string; + + public constructor(message: string) { + super(); + this._message = message; + } + + public get message(): string { + return `${this._message}`; + } +} + +export type Lengthable = { + length: number, +}; + +export function isLenghtable(value: unknown): value is Lengthable { + return value !== undefined && value !== null && + typeof (value as Lengthable).length === 'number'; +} diff --git a/src/helpers/BackendController.ts b/src/helpers/BackendController.ts new file mode 100644 index 0000000..66fc1c0 --- /dev/null +++ b/src/helpers/BackendController.ts @@ -0,0 +1,134 @@ +import config from "config"; +import Controller from "../Controller"; +import User from "../auth/models/User"; +import {Request, Response} from "express"; +import {BadRequestError, NotFoundHttpError} from "../HttpError"; +import Mail from "../mail/Mail"; +import {ACCOUNT_REVIEW_NOTICE_MAIL_TEMPLATE} from "../Mails"; +import UserEmail from "../auth/models/UserEmail"; +import UserApprovedComponent from "../auth/models/UserApprovedComponent"; +import {RequireAdminMiddleware, RequireAuthMiddleware} from "../auth/AuthComponent"; +import NunjucksComponent from "../components/NunjucksComponent"; + +export default class BackendController extends Controller { + private static readonly menu: BackendMenuElement[] = []; + + public static registerMenuElement(element: BackendMenuElement): void { + this.menu.push(element); + } + + public constructor() { + super(); + if (User.isApprovalMode()) { + BackendController.registerMenuElement({ + getLink: async () => Controller.route('accounts-approval'), + getDisplayString: async () => { + const pendingUsersCount = (await User.select() + .where('approved', false) + .get()).length; + return `Accounts approval (${pendingUsersCount})`; + }, + getDisplayIcon: async () => 'user-check', + }); + } + } + + public getRoutesPrefix(): string { + return '/backend'; + } + + public routes(): void { + this.useMiddleware(RequireAuthMiddleware, RequireAdminMiddleware); + + this.get('/', this.getIndex, 'backend'); + if (User.isApprovalMode()) { + this.get('/accounts-approval', this.getAccountApproval, 'accounts-approval'); + this.post('/accounts-approval/approve', this.postApproveAccount, 'approve-account'); + this.post('/accounts-approval/reject', this.postRejectAccount, 'reject-account'); + } + } + + protected async getIndex(req: Request, res: Response): Promise { + res.render('backend/index', { + menu: await Promise.all(BackendController.menu.map(async m => ({ + link: await m.getLink(), + display_string: await m.getDisplayString(), + display_icon: await m.getDisplayIcon(), + }))), + }); + } + + protected async getAccountApproval(req: Request, res: Response): Promise { + const accounts = await User.select() + .where('approved', 0) + .with('mainEmail') + .get(); + res.render('backend/accounts_approval', { + accounts: accounts, + }); + } + + protected async postApproveAccount(req: Request, res: Response): Promise { + const {account, email} = await this.accountRequest(req); + + account.as(UserApprovedComponent).approved = true; + await account.save(); + + if (email && email.email) { + await new Mail(this.getApp().as(NunjucksComponent).getEnvironment(), ACCOUNT_REVIEW_NOTICE_MAIL_TEMPLATE, { + approved: true, + link: config.get('public_url') + Controller.route('auth'), + }).send(email.email); + } + + req.flash('success', `Account successfully approved.`); + res.redirect(Controller.route('accounts-approval')); + } + + protected async postRejectAccount(req: Request, res: Response): Promise { + const {account, email} = await this.accountRequest(req); + + await account.delete(); + + if (email && email.email) { + await new Mail(this.getApp().as(NunjucksComponent).getEnvironment(), ACCOUNT_REVIEW_NOTICE_MAIL_TEMPLATE, { + approved: false, + }).send(email.email); + } + + req.flash('success', `Account successfully deleted.`); + res.redirect(Controller.route('accounts-approval')); + } + + protected async accountRequest(req: Request): Promise<{ + account: User, + email: UserEmail | null, + }> { + if (!req.body.user_id) throw new BadRequestError('Missing user_id field', 'Check your form', req.url); + const account = await User.select().where('id', req.body.user_id).with('mainEmail').first(); + if (!account) throw new NotFoundHttpError('User', req.url); + const email = await account.mainEmail.get(); + + return { + account: account, + email: email, + }; + } +} + +export interface BackendMenuElement { + /** + * Returns the link of this menu element (usually using {@code Controller.route}) + */ + getLink(): Promise; + + /** + * The string part of the link display + */ + getDisplayString(): Promise; + + /** + * An optional feather icon name + */ + getDisplayIcon(): Promise; +} diff --git a/src/Mail.ts b/src/mail/Mail.ts similarity index 59% rename from src/Mail.ts rename to src/mail/Mail.ts index 3ce28e0..da66d79 100644 --- a/src/Mail.ts +++ b/src/mail/Mail.ts @@ -1,19 +1,16 @@ import nodemailer, {SentMessageInfo, Transporter} from "nodemailer"; import config from "config"; import {Options} from "nodemailer/lib/mailer"; -import nunjucks from 'nunjucks'; +import {Environment} from 'nunjucks'; import * as util from "util"; -import {WrappingError} from "./Utils"; +import {WrappingError} from "../Utils"; import mjml2html from "mjml"; -import * as querystring from "querystring"; -import Logger from "./Logger"; - -export function mailRoute(template: string): string { - return `/mail/${template}`; -} +import {logger} from "../Logger"; +import Controller from "../Controller"; +import {ParsedUrlQueryInput} from "querystring"; export default class Mail { - private static transporter: Transporter; + private static transporter?: Transporter; private static getTransporter(): Transporter { if (!this.transporter) throw new MailError('Mail system was not prepared.'); @@ -24,14 +21,14 @@ export default class Mail { const transporter = nodemailer.createTransport({ host: config.get('mail.host'), port: config.get('mail.port'), - secure: config.get('mail.secure'), + requireTLS: config.get('mail.secure'), // STARTTLS auth: { user: config.get('mail.username'), pass: config.get('mail.password'), }, tls: { - rejectUnauthorized: !config.get('mail.allow_invalid_tls') - } + rejectUnauthorized: !config.get('mail.allow_invalid_tls'), + }, }); try { @@ -41,16 +38,21 @@ export default class Mail { throw new MailError('Connection to mail service unsuccessful.', e); } - Logger.info(`Mail ready to be distributed via ${config.get('mail.host')}:${config.get('mail.port')}`); + logger.info(`Mail ready to be distributed via ${config.get('mail.host')}:${config.get('mail.port')}`); } - public static end() { - this.transporter.close(); + public static end(): void { + if (this.transporter) this.transporter.close(); } - public static parse(template: string, data: any, textOnly: boolean): string { + public static parse( + environment: Environment, + template: string, + data: { [p: string]: unknown }, + textOnly: boolean, + ): string { data.text = textOnly; - const nunjucksResult = nunjucks.render(template, data); + const nunjucksResult = environment.render(template, data); if (textOnly) return nunjucksResult; const mjmlResult = mjml2html(nunjucksResult, {}); @@ -62,11 +64,13 @@ export default class Mail { return mjmlResult.html; } - private readonly template: MailTemplate; private readonly options: Options = {}; - private readonly data: { [p: string]: any }; - constructor(template: MailTemplate, data: { [p: string]: any } = {}) { + public constructor( + private readonly environment: Environment, + private readonly template: MailTemplate, + private readonly data: ParsedUrlQueryInput = {}, + ) { this.template = template; this.data = data; this.options.subject = this.template.getSubject(data); @@ -93,18 +97,26 @@ export default class Mail { // Set options this.options.to = destEmail; + this.options.from = { + name: config.get('mail.from_name'), + address: config.get('mail.from'), + }; // Set data this.data.mail_subject = this.options.subject; this.data.mail_to = this.options.to; - this.data.mail_link = `${config.get('public_url')}${mailRoute(this.template.template)}?${querystring.stringify(this.data)}`; + this.data.mail_link = config.get('public_url') + + Controller.route('mail', [this.template.template], this.data); + this.data.app = config.get('app'); // Log - Logger.dev('Send mail', this.options); + logger.debug('Send mail', this.options); // Render email - this.options.html = Mail.parse('mails/' + this.template.template + '.mjml.njk', this.data, false); - this.options.text = Mail.parse('mails/' + this.template.template + '.mjml.njk', this.data, true); + this.options.html = Mail.parse(this.environment, 'mails/' + this.template.template + '.mjml.njk', + this.data, false); + this.options.text = Mail.parse(this.environment, 'mails/' + this.template.template + '.mjml.njk', + this.data, true); // Send email results.push(await Mail.getTransporter().sendMail(this.options)); @@ -116,9 +128,9 @@ export default class Mail { export class MailTemplate { private readonly _template: string; - private readonly subject: (data: any) => string; + private readonly subject: (data: { [p: string]: unknown }) => string; - constructor(template: string, subject: (data: any) => string) { + public constructor(template: string, subject: (data: { [p: string]: unknown }) => string) { this._template = template; this.subject = subject; } @@ -127,13 +139,13 @@ export class MailTemplate { return this._template; } - public getSubject(data: any): string { - return 'Watch My Stream - ' + this.subject(data); + public getSubject(data: { [p: string]: unknown }): string { + return `${config.get('app.name')} - ${this.subject(data)}`; } } class MailError extends WrappingError { - constructor(message: string = 'An error occurred while sending mail.', cause?: Error) { + public constructor(message: string = 'An error occurred while sending mail.', cause?: Error) { super(message, cause); } -} \ No newline at end of file +} diff --git a/src/mail/MailController.ts b/src/mail/MailController.ts new file mode 100644 index 0000000..f3b7c64 --- /dev/null +++ b/src/mail/MailController.ts @@ -0,0 +1,16 @@ +import {Request, Response} from "express"; +import Controller from "../Controller"; +import Mail from "./Mail"; +import NunjucksComponent from "../components/NunjucksComponent"; + +export default class MailController extends Controller { + public routes(): void { + this.get("/mail/:template", this.getMail, 'mail'); + } + + protected async getMail(request: Request, response: Response): Promise { + const template = request.params['template']; + response.send(Mail.parse(this.getApp().as(NunjucksComponent).getEnvironment(), + `mails/${template}.mjml.njk`, request.query, false)); + } +} diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..0ea8124 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,20 @@ +import {delimiter} from "path"; + +// Load config from specified path or default + swaf/config (default defaults) +process.env['NODE_CONFIG_DIR'] = + __dirname + '/../../node_modules/swaf/config/' + + delimiter + + (process.env['NODE_CONFIG_DIR'] || __dirname + '/../../config/'); + +import {logger} from "./Logger"; +import TestApp from "./TestApp"; +import config from "config"; + +(async () => { + logger.debug('Config path:', process.env['NODE_CONFIG_DIR']); + + const app = new TestApp(config.get('listen_addr'), config.get('port')); + await app.start(); +})().catch(err => { + logger.error(err); +}); diff --git a/src/migrations/CreateLogsTable.ts b/src/migrations/CreateLogsTable.ts deleted file mode 100644 index 37511b7..0000000 --- a/src/migrations/CreateLogsTable.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Migration from "../db/Migration"; -import {query} from "../db/MysqlConnectionManager"; - -/** - * Must be the first migration - */ -export default class CreateLogsTable extends Migration { - async install(): Promise { - await query('CREATE TABLE logs(' + - 'id INT NOT NULL AUTO_INCREMENT,' + - 'level TINYINT UNSIGNED NOT NULL,' + - 'message TEXT NOT NULL,' + - 'log_id BINARY(16),' + - 'error_name VARCHAR(128),' + - 'error_message VARCHAR(512),' + - 'error_stack TEXT,' + - 'created_at DATETIME NOT NULL DEFAULT NOW(),' + - 'PRIMARY KEY (id)' + - ')'); - } - - async rollback(): Promise { - await query('DROP TABLE logs'); - } -} \ No newline at end of file diff --git a/src/migrations/CreateMigrationsTable.ts b/src/migrations/CreateMigrationsTable.ts index 5931d24..0f1c6e8 100644 --- a/src/migrations/CreateMigrationsTable.ts +++ b/src/migrations/CreateMigrationsTable.ts @@ -5,7 +5,7 @@ import {query} from "../db/MysqlConnectionManager"; * Must be the first migration */ export default class CreateMigrationsTable extends Migration { - async shouldRun(currentVersion: number): Promise { + public async shouldRun(currentVersion: number): Promise { try { await query('SELECT 1 FROM migrations LIMIT 1'); } catch (e) { @@ -17,16 +17,17 @@ export default class CreateMigrationsTable extends Migration { return await super.shouldRun(currentVersion); } - async install(): Promise { - await query('CREATE TABLE migrations(' + - 'id INT NOT NULL,' + - 'name VARCHAR(64) NOT NULL,' + - 'migration_date DATE,' + - 'PRIMARY KEY (id)' + - ')'); + public async install(): Promise { + await this.query(`CREATE TABLE migrations + ( + id INT NOT NULL, + name VARCHAR(64) NOT NULL, + migration_date DATE, + PRIMARY KEY (id) + )`); } - async rollback(): Promise { - await query('DROP TABLE migrations'); + public async rollback(): Promise { + await this.query('DROP TABLE migrations'); } -} \ No newline at end of file +} diff --git a/src/migrations/DropLegacyLogsTable.ts b/src/migrations/DropLegacyLogsTable.ts new file mode 100644 index 0000000..c6c0cc1 --- /dev/null +++ b/src/migrations/DropLegacyLogsTable.ts @@ -0,0 +1,11 @@ +import Migration from "../db/Migration"; + +export default class DropLegacyLogsTable extends Migration { + public async install(): Promise { + await this.query('DROP TABLE IF EXISTS logs'); + } + + public async rollback(): Promise { + // Do nothing + } +} diff --git a/src/migrations/DummyMigration.ts b/src/migrations/DummyMigration.ts new file mode 100644 index 0000000..bfa47bc --- /dev/null +++ b/src/migrations/DummyMigration.ts @@ -0,0 +1,11 @@ +import Migration from "../db/Migration"; + +export default class DummyMigration extends Migration { + public async install(): Promise { + // Do nothing + } + + public async rollback(): Promise { + // Do nothing + } +} diff --git a/src/models/Log.ts b/src/models/Log.ts deleted file mode 100644 index e702423..0000000 --- a/src/models/Log.ts +++ /dev/null @@ -1,69 +0,0 @@ -import Model from "../db/Model"; -import {LogLevel, LogLevelKeys} from "../Logger"; -import Validator from "../db/Validator"; - -export default class Log extends Model { - private level?: number; - public message?: string; - private log_id?: Buffer; - private error_name?: string; - private error_message?: string; - private error_stack?: string; - private created_at?: Date; - - protected defineProperties(): void { - this.defineProperty('level', new Validator().defined()); - this.defineProperty('message', new Validator().defined().between(0, 65535)); - this.defineProperty('log_id', new Validator().acceptUndefined().length(16)); - this.defineProperty('error_name', new Validator().acceptUndefined().between(0, 128)); - this.defineProperty('error_message', new Validator().acceptUndefined().between(0, 512)); - this.defineProperty('error_stack', new Validator().acceptUndefined().between(0, 65535)); - this.defineProperty('created_at', new Validator()); - } - - public getLevel(): LogLevelKeys { - if (typeof this.level !== 'number') return 'ERROR'; - return LogLevel[this.level]; - } - - public setLevel(level: LogLevelKeys) { - this.level = LogLevel[level]; - } - - public getLogID(): string | null { - if (!this.log_id) return null; - const chars = this.log_id!.toString('hex'); - let out = ''; - let i = 0; - for (const l of [8, 4, 4, 4, 12]) { - if (i > 0) out += '-'; - out += chars.substr(i, l); - i += l; - } - return out; - } - - public setLogID(buffer: Buffer) { - this.log_id = buffer; - } - - public getErrorName(): string { - return this.error_name || ''; - } - - public getErrorMessage(): string { - return this.error_message || ''; - } - - public getErrorStack(): string { - return this.error_stack || ''; - } - - public setError(error?: Error) { - if (!error) return; - - this.error_name = error.name; - this.error_message = error.message; - this.error_stack = error.stack; - } -} diff --git a/src/types/Express.d.ts b/src/types/Express.d.ts index ce55917..2d61e3c 100644 --- a/src/types/Express.d.ts +++ b/src/types/Express.d.ts @@ -1,22 +1,54 @@ -import {Environment} from "nunjucks"; -import Model from "../db/Model"; +import {Files} from "formidable"; +import {Type} from "../Utils"; +import Middleware from "../Middleware"; +import {FlashMessages} from "../components/SessionComponent"; +import {Session, SessionData} from "express-session"; +import {PasswordAuthProofSessionData} from "../auth/password/PasswordAuthProof"; declare global { namespace Express { export interface Request { - env: Environment; - models: { [p: string]: Model | null }; - modelCollections: { [p: string]: Model[] | null }; + getSession(): Session & Partial; - flash(): { [key: string]: string[] }; + getSessionOptional(): Session & Partial | undefined; - flash(message: string): any; - flash(event: string, message: any): any; - } + files: Files; - export interface Response { - redirectBack(defaultUrl?: string): any; + + middlewares: Middleware[]; + + as(type: Type): M; + + + flash(): FlashMessages; + + flash(message: string): unknown[]; + + flash(event: string, message: unknown): void; + + + getPreviousUrl(): string | null; + + getIntendedUrl(): string | null; } } -} \ No newline at end of file +} + +declare module 'express-session' { + interface SessionData { + id?: string; + + previousUrl?: string; + + wantsSessionPersistence?: boolean; + + persistent?: boolean; + + isAuthenticated?: boolean; + + authPasswordProof?: PasswordAuthProofSessionData; + + csrf?: string; + } +} diff --git a/test/Authentication.test.ts b/test/Authentication.test.ts new file mode 100644 index 0000000..ad4e907 --- /dev/null +++ b/test/Authentication.test.ts @@ -0,0 +1,1122 @@ +import TestApp from "../src/TestApp"; +import useApp from "./_app"; +import Controller from "../src/Controller"; +import supertest from "supertest"; +import CsrfProtectionComponent from "../src/components/CsrfProtectionComponent"; +import User from "../src/auth/models/User"; +import UserNameComponent from "../src/auth/models/UserNameComponent"; +import UserPasswordComponent from "../src/auth/password/UserPasswordComponent"; +import {popEmail} from "./_mail_server"; +import AuthComponent from "../src/auth/AuthComponent"; +import {followMagicLinkFromMail, testLogout} from "./_authentication_common"; +import UserEmail from "../src/auth/models/UserEmail"; +import * as querystring from "querystring"; + +let app: TestApp; +useApp(async (addr, port) => { + return app = new class extends TestApp { + protected async init(): Promise { + this.use(new class extends Controller { + public routes(): void { + this.get('/', (req, res) => { + res.render('home'); + }, 'home'); + this.get('/csrf', (req, res) => { + res.send(CsrfProtectionComponent.getCsrfToken(req.getSession())); + }, 'csrf'); + this.get('/is-auth', async (req, res) => { + const proofs = await this.getApp().as(AuthComponent).getAuthGuard().getProofs(req); + if (proofs.length > 0) res.sendStatus(200); + else res.sendStatus(401); + }, 'is-auth'); + } + }()); + + await super.init(); + } + }(addr, port); +}); + +let agent: supertest.SuperTest; + +beforeAll(() => { + agent = supertest(app.getExpressApp()); +}); + +describe('Register with username and password (password)', () => { + let cookies: string[]; + let csrf: string; + + test('General case', async () => { + const res = await agent.get('/csrf').expect(200); + cookies = res.get('Set-Cookie'); + csrf = res.text; + + // Register user + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'password', + identifier: 'entrapta', + password: 'darla_is_cute', + password_confirmation: 'darla_is_cute', + terms: 'on', + }) + .expect(302) + .expect('Location', '/'); + + // Verify saved user + const user = await User.select() + .where('name', 'entrapta') + .first(); + + expect(user).toBeDefined(); + expect(user?.as(UserNameComponent).name).toStrictEqual('entrapta'); + await expect(user?.as(UserPasswordComponent).verifyPassword('darla_is_cute')).resolves.toStrictEqual(true); + }); + + test('Can\'t register when logged in', async () => { + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'password', + identifier: 'entrapta2', + password: 'darla_is_cute', + password_confirmation: 'darla_is_cute', + terms: 'on', + }) + .expect(302) + .expect('Location', '/'); + + const user2 = await User.select() + .where('name', 'entrapta2') + .first(); + expect(user2).toBeNull(); + }); + + test('Logout', async () => { + await testLogout(agent, cookies, csrf); + }); + + test('Cannot register taken username', async () => { + // Check that there is no hordak in DB + expect(await User.select() + .where('name', 'hordak') + .count()).toStrictEqual(0); + + const res1 = await agent.get('/csrf').expect(200); + const cookies = res1.get('Set-Cookie'); + const csrf = res1.text; + + // Register user + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'password', + identifier: 'hordak', + password: 'horde_prime_will_rise', + password_confirmation: 'horde_prime_will_rise', + terms: 'on', + }) + .expect(302) + .expect('Location', '/'); + await testLogout(agent, cookies, csrf); + + // Verify saved user + expect(await User.select() + .where('name', 'hordak') + .count()).toStrictEqual(1); + + + // Attempt register same user + const res = await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'password', + identifier: 'hordak', + password: 'horde_prime_will_rise_unless', + password_confirmation: 'horde_prime_will_rise_unless', + terms: 'on', + }) + .expect(400); + // username field should be translated from identifier + expect(res.body.messages?.identifier?.name).toStrictEqual('AlreadyExistsValidationError'); + + // Verify nothing changed + expect(await User.select() + .where('name', 'hordak') + .count()).toStrictEqual(1); + }); +}); + +describe('Register with email (magic_link)', () => { + test('General case', async () => { + const res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + await agent.post('/auth/register?' + querystring.stringify({redirect_uri: '/redirect-uri'})) + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'glimmer@example.org', + name: 'glimmer', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri=%2Fredirect-uri'); + + await followMagicLinkFromMail(agent, cookies); + + await testLogout(agent, cookies, csrf); + + // Verify saved user + const user = await User.select() + .with('mainEmail') + .where('name', 'glimmer') + .first(); + + expect(user).toBeDefined(); + + const email = user?.mainEmail.getOrFail(); + expect(email).toBeDefined(); + expect(email?.email).toStrictEqual('glimmer@example.org'); + + expect(user?.as(UserNameComponent).name).toStrictEqual('glimmer'); + await expect(user?.as(UserPasswordComponent).verifyPassword('')).resolves.toStrictEqual(false); + }); + + test('Cannot register without specifying username', async () => { + let res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + res = await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'no_user_name@example.org', + }) + .expect(400); + expect(res.body.messages?.name?.name).toStrictEqual('UndefinedValueValidationError'); + + expect(await popEmail()).toBeNull(); + }); + + test('Cannot register taken username', async () => { + const res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'angella@example.org', + name: 'angella', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + await testLogout(agent, cookies, csrf); + + // Verify saved user + const user = await User.select() + .with('mainEmail') + .where('name', 'angella') + .first(); + + expect(user).toBeDefined(); + + // Attempt register with another mail but same username + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'angella_something_else@example.org', + name: 'angella', + }) + .expect(400); + + expect(await popEmail()).toBeNull(); + }); + + test('Cannot register taken email', async () => { + const res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'bow@example.org', + name: 'bow', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + await testLogout(agent, cookies, csrf); + + // Verify saved user + const user = await User.select() + .with('mainEmail') + .where('name', 'bow') + .first(); + + expect(user).toBeDefined(); + + // Attempt register with another mail but same username + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'bow@example.org', + name: 'bow2', + }) + .expect(400); + + expect(await popEmail()).toBeNull(); + }); +}); + +describe('Authenticate with username and password (password)', () => { + test('Force auth_method', async () => { + let res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Bad password + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'entrapta', + password: 'darla_is_not_cute', + auth_method: 'password', + }) + .expect(400); + expect(res.body.messages?.password?.name).toStrictEqual('InvalidFormatValidationError'); + + // Authenticate + await agent.post('/auth/login?' + querystring.stringify({redirect_uri: '/redirect-uri'})) + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'entrapta', + password: 'darla_is_cute', + auth_method: 'password', + }) + .expect(302) + .expect('Location', '/redirect-uri'); + + await testLogout(agent, cookies, csrf); + }); + + test('Automatic auth_method', async () => { + let res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Bad password + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'entrapta', + password: 'darla_is_not_cute', + }) + .expect(400); + expect(res.body.messages?.password?.name).toStrictEqual('InvalidFormatValidationError'); + + // Authenticate + await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'entrapta', + password: 'darla_is_cute', + }) + .expect(302) + .expect('Location', '/'); + + await testLogout(agent, cookies, csrf); + }); + + test('Non-existing username', async () => { + let res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Authenticate + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'i_do_not_exist', + password: 'there_is_no_point', + auth_method: 'password', + }) + .expect(400); + expect(res.body.messages?.identifier?.name).toStrictEqual('UnknownRelationValidationError'); + + // Authenticate (automatic method) + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'i_do_not_exist', + password: 'there_is_no_point', + auth_method: 'password', + }) + .expect(400); + expect(res.body.messages?.identifier?.name).toStrictEqual('UnknownRelationValidationError'); + }); + + test('No password user', async () => { + let res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Authenticate + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'glimmer', + password: '', + auth_method: 'password', + }) + .expect(400); + expect(res.body.messages?.password?.name).toStrictEqual('InvalidFormatValidationError'); + + // Authenticate (automatic method) + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'glimmer', + password: '', + }) + .expect(400); + expect(res.body.messages?.password?.name).toStrictEqual('InvalidFormatValidationError'); + + // Authenticate without password + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'angella', + auth_method: 'password', + }) + .expect(400); + expect(res.body.messages?.password?.name).toStrictEqual('InvalidFormatValidationError'); + + // Authenticate without password (automatic method) + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'angella', + }) + .expect(400); + expect(res.body.messages?.password?.name).toStrictEqual('InvalidFormatValidationError'); + }); +}); + +describe('Authenticate with email (magic_link)', () => { + test('Force auth_method', async () => { + const res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Authenticate + await agent.post('/auth/login?' + querystring.stringify({redirect_uri: '/redirect-uri'})) + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'glimmer@example.org', + auth_method: 'magic_link', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri=%2Fredirect-uri'); + + await followMagicLinkFromMail(agent, cookies); + + await testLogout(agent, cookies, csrf); + }); + + test('Automatic auth_method', async () => { + const res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Authenticate + await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'angella@example.org', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + await testLogout(agent, cookies, csrf); + }); + + test('Non-existing email (forced auth_method)', async () => { + let res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Authenticate + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'i_do_not_exist@invalid.org', + auth_method: 'magic_link', + }) + .expect(400); + expect(res.body.messages?.identifier?.name).toStrictEqual('UnknownRelationValidationError'); + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + }); + + test('Non-existing email (automatic auth_method)', async () => { + let res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Authenticate + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'i_do_not_exist@invalid.org', + }) + .expect(400); + expect(res.body.messages?.identifier?.name).toStrictEqual('UnknownRelationValidationError'); + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + }); +}); + +describe('Authenticate with email and password (password)', () => { + test('Prepare user', async () => { + const res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'double-trouble@example.org', + name: 'double-trouble', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + await testLogout(agent, cookies, csrf); + + // Verify saved user + const user = await User.select() + .with('mainEmail') + .where('name', 'double-trouble') + .first(); + + await user?.as(UserPasswordComponent).setPassword('trick-or-treat'); + await user?.save(); + + expect(user).toBeDefined(); + + const email = user?.mainEmail.getOrFail(); + expect(email).toBeDefined(); + expect(email?.email).toStrictEqual('double-trouble@example.org'); + + expect(user?.as(UserNameComponent).name).toStrictEqual('double-trouble'); + await expect(user?.as(UserPasswordComponent).verifyPassword('trick-or-treat')).resolves.toStrictEqual(true); + }); + + test('Force auth_method', async () => { + let res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Bad password + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'double-trouble@example.org', + password: 'i_have_no_imagination', + auth_method: 'password', + }) + .expect(400); + expect(res.body.messages?.password?.name).toStrictEqual('InvalidFormatValidationError'); + + // Authenticate + await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'double-trouble@example.org', + password: 'trick-or-treat', + auth_method: 'password', + }) + .expect(302) + .expect('Location', '/'); + + await testLogout(agent, cookies, csrf); + }); + + test('Automatic auth_method', async () => { + let res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); + + // Bad password + res = await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'double-trouble@example.org', + password: 'i_have_no_imagination', + }) + .expect(400); + expect(res.body.messages?.password?.name).toStrictEqual('InvalidFormatValidationError'); + + // Authenticate + await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + identifier: 'double-trouble@example.org', + password: 'trick-or-treat', + }) + .expect(302) + .expect('Location', '/'); + + await testLogout(agent, cookies, csrf); + }); +}); + + +describe('Change password', () => { + let cookies: string[], csrf: string; + test('Prepare user', async () => { + const res = await agent.get('/csrf').expect(200); + cookies = res.get('Set-Cookie'); + csrf = res.text; + + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'aang@example.org', + name: 'aang', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + }); + + test('Set password to blank from blank', async () => { + await agent.post('/account/change-password') + .set('Cookie', cookies) + .send({ + csrf: csrf, + 'current_password': '', + 'new_password': '', + 'new_password_confirmation': '', + }) + .expect(400); + + const user = await User.select() + .where('name', 'aang') + .first(); + expect(user).toBeDefined(); + expect(user?.as(UserPasswordComponent).hasPassword()).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('bad_password')).toBeFalsy(); + }); + + test('Set password to something from blank', async () => { + await agent.post('/account/change-password') + .set('Cookie', cookies) + .send({ + csrf: csrf, + 'current_password': '', + 'new_password': 'a_very_strong_password', + 'new_password_confirmation': 'a_very_strong_password', + }) + .expect(302) + .expect('Location', '/account/'); + + const user = await User.select() + .where('name', 'aang') + .first(); + expect(user).toBeDefined(); + expect(user?.as(UserPasswordComponent).hasPassword()).toBeTruthy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('bad_password')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('a_very_strong_password')).toBeTruthy(); + }); + + test('Set password to blank from something', async () => { + await agent.post('/account/change-password') + .set('Cookie', cookies) + .send({ + csrf: csrf, + 'current_password': 'a_very_strong_password', + 'new_password': '', + }) + .expect(400); + + const user = await User.select() + .where('name', 'aang') + .first(); + expect(user).toBeDefined(); + expect(user?.as(UserPasswordComponent).hasPassword()).toBeTruthy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('bad_password')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('a_very_strong_password')).toBeTruthy(); + }); + + test('Set password to something from something', async () => { + await agent.post('/account/change-password') + .set('Cookie', cookies) + .send({ + csrf: csrf, + 'current_password': 'a_very_strong_password', + 'new_password': 'a_very_strong_password_but_different', + 'new_password_confirmation': 'a_very_strong_password_but_different', + }) + .expect(302) + .expect('Location', '/account/'); + + const user = await User.select() + .where('name', 'aang') + .first(); + expect(user).toBeDefined(); + expect(user?.as(UserPasswordComponent).hasPassword()).toBeTruthy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('bad_password')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('a_very_strong_password')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('a_very_strong_password_but_different')).toBeTruthy(); + }); + + test('Set password to unconfirmed', async () => { + await agent.post('/account/change-password') + .set('Cookie', cookies) + .send({ + csrf: csrf, + 'current_password': 'a_very_strong_password_but_different', + 'new_password': 'a_very_strong_password', + 'new_password_confirmation': '', + }) + .expect(400); + + await agent.post('/account/change-password') + .set('Cookie', cookies) + .send({ + csrf: csrf, + 'current_password': 'a_very_strong_password_but_different', + 'new_password': 'a_very_strong_password', + 'new_password_confirmation': 'a_very_strong_password_but_different2', + }) + .expect(400); + + const user = await User.select() + .where('name', 'aang') + .first(); + expect(user).toBeDefined(); + expect(user?.as(UserPasswordComponent).hasPassword()).toBeTruthy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('bad_password')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('a_very_strong_password')).toBeFalsy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('a_very_strong_password_but_different')).toBeTruthy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('a_very_strong_password_but_different2')).toBeFalsy(); + }); + + test('Set password to too short password', async () => { + await agent.post('/account/change-password') + .set('Cookie', cookies) + .send({ + csrf: csrf, + 'current_password': 'a_very_strong_password_but_different', + 'new_password': '123', + 'new_password_confirmation': '123', + }) + .expect(400); + + const user = await User.select() + .where('name', 'aang') + .first(); + expect(user).toBeDefined(); + expect(user?.as(UserPasswordComponent).hasPassword()).toBeTruthy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('a_very_strong_password_but_different')).toBeTruthy(); + expect(await user?.as(UserPasswordComponent).verifyPassword('123')).toBeFalsy(); + }); +}); + + +describe('Manage email addresses', () => { + + async function testMainSecondaryState(main: string, secondary: string) { + const user = await User.select('main_email_id').where('name', 'katara').first(); + + const mainEmail = await UserEmail.select().where('email', main).first(); + expect(mainEmail).not.toBeNull(); + expect(user?.main_email_id).toBe(mainEmail?.id); + + const secondaryEmail = await UserEmail.select().where('email', secondary).first(); + expect(secondaryEmail).not.toBeNull(); + expect(user?.main_email_id).not.toBe(secondaryEmail?.id); + + return secondaryEmail; + } + + let cookies: string[], csrf: string; + test('Prepare user', async () => { + const res = await agent.get('/csrf').expect(200); + cookies = res.get('Set-Cookie'); + csrf = res.text; + + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'katara@example.org', + name: 'katara', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + // Add fake, not owned secondary email + const user = User.create({ + name: 'not_katara', + }); + await user.save(); + await UserEmail.create({ + email: 'not_katara@example.org', + user_id: user.id, + }).save(); + }); + + describe('Add', () => { + test('Add invalid email addresses', async () => { + await agent.post('/account/add-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + }) + .expect(400); + await agent.post('/account/add-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + email: '', + }) + .expect(400); + await agent.post('/account/add-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + email: 'katara@example.org', + }) + .expect(400); + + expect(await UserEmail.select().where('email', 'katara@example.org').count()).toBe(1); + }); + + test('Add valid email addresses', async () => { + const expectedUserId = (await User.select('id').where('name', 'katara').first())?.id; + + for (const email of [ + 'katara2@example.org', + 'katara3@example.org', + 'katara4@example.org', + ]) { + await agent.post('/account/add-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + email: email, + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri=%2Faccount%2F'); + + await followMagicLinkFromMail(agent, cookies, '/account/'); + + const userEmail = await UserEmail.select().where('email', email).first(); + expect(userEmail).not.toBeNull(); + expect(userEmail?.user_id).toBe(expectedUserId); + } + }); + }); + + describe('Set main', () => { + test('Set main email address as main email address', async () => { + await testMainSecondaryState('katara@example.org', 'katara3@example.org'); + + // Set secondary as main + await agent.post('/account/set-main-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + id: (await UserEmail.select().where('email', 'katara@example.org').first())?.id, + }) + .expect(400); + + await testMainSecondaryState('katara@example.org', 'katara3@example.org'); + }); + + test('Set secondary email address as main email address', async () => { + const beforeSecondaryEmail = await testMainSecondaryState('katara@example.org', 'katara3@example.org'); + + // Set secondary as main + await agent.post('/account/set-main-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + id: beforeSecondaryEmail?.id, + }) + .expect(302) + .expect('Location', '/account/'); + + await testMainSecondaryState('katara3@example.org', 'katara@example.org'); + }); + + test('Set non-owned address as main email address', async () => { + const beforeSecondaryEmail = await testMainSecondaryState('katara3@example.org', 'not_katara@example.org'); + + // Set secondary as main + await agent.post('/account/set-main-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + id: beforeSecondaryEmail?.id, + }) + .expect(403); + + await testMainSecondaryState('katara3@example.org', 'not_katara@example.org'); + }); + + test('Set non-existing address as main email address', async () => { + await testMainSecondaryState('katara3@example.org', 'katara4@example.org'); + + // Set secondary as main + await agent.post('/account/set-main-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + id: 999, + }) + .expect(404); + + await testMainSecondaryState('katara3@example.org', 'katara4@example.org'); + }); + }); + + describe('Remove', () => { + test('Remove secondary email address', async () => { + expect(await UserEmail.select().where('email', 'katara2@example.org').count()).toBe(1); + + // Set secondary as main + await agent.post('/account/remove-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + id: (await UserEmail.select().where('email', 'katara2@example.org').first())?.id, + }) + .expect(302) + .expect('Location', '/account/'); + + expect(await UserEmail.select().where('email', 'katara2@example.org').count()).toBe(0); + }); + + test('Remove non-owned email address', async () => { + expect(await UserEmail.select().where('email', 'not_katara@example.org').count()).toBe(1); + + // Set secondary as main + await agent.post('/account/remove-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + id: (await UserEmail.select().where('email', 'not_katara@example.org').first())?.id, + }) + .expect(403); + + expect(await UserEmail.select().where('email', 'not_katara@example.org').count()).toBe(1); + }); + + test('Remove non-existing email address', async () => { + // Set secondary as main + await agent.post('/account/remove-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + id: 999, + }) + .expect(404); + }); + + test('Remove main email address', async () => { + expect(await UserEmail.select().where('email', 'katara3@example.org').count()).toBe(1); + + // Set secondary as main + await agent.post('/account/remove-email') + .set('Cookie', cookies) + .send({ + csrf: csrf, + id: (await UserEmail.select().where('email', 'katara3@example.org').first())?.id, + }) + .expect(400); + + expect(await UserEmail.select().where('email', 'katara3@example.org').count()).toBe(1); + }); + }); +}); + +describe('Session persistence', () => { + let cookies: string[], csrf: string; + + test('Not persistent at registration', async () => { + let res = await agent.get('/csrf').expect(200); + cookies = res.get('Set-Cookie'); + csrf = res.text; + + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'zuko@example.org', + name: 'zuko', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + expect(cookies[0]).toMatch(/^connect\.sid=.+; Path=\/; HttpOnly$/); + + res = await agent.get('/csrf') + .set('Cookie', cookies) + .expect(200); + expect(res.get('Set-Cookie')[0]).toMatch(/^connect\.sid=.+; Path=\/; Expires=.+; HttpOnly$/); + + // Logout + await agent.post('/auth/logout') + .set('Cookie', cookies) + .send({csrf}) + .expect(302) + .expect('Location', '/'); + }); + + test('Login with persistence', async () => { + await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'zuko@example.org', + persist_session: 'on', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + const res = await agent.get('/csrf') + .set('Cookie', cookies) + .expect(200); + expect(res.get('Set-Cookie')[0]).toMatch(/^connect\.sid=.+; Path=\/; Expires=.+; HttpOnly$/); + + // Logout + await agent.post('/auth/logout') + .set('Cookie', cookies) + .send({csrf}) + .expect(302) + .expect('Location', '/'); + }); + + test('Login without persistence', async () => { + await agent.post('/auth/login') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'zuko@example.org', + persist_session: undefined, + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + const res = await agent.get('/csrf') + .set('Cookie', cookies) + .expect(200); + expect(res.get('Set-Cookie')[0]).toMatch(/^connect\.sid=.+; Path=\/; HttpOnly$/); + + // Logout + await agent.post('/auth/logout') + .set('Cookie', cookies) + .send({csrf}) + .expect(302) + .expect('Location', '/'); + }); +}); diff --git a/test/AuthenticationNoUsername.test.ts b/test/AuthenticationNoUsername.test.ts new file mode 100644 index 0000000..8930d7d --- /dev/null +++ b/test/AuthenticationNoUsername.test.ts @@ -0,0 +1,147 @@ +import TestApp from "../src/TestApp"; +import useApp from "./_app"; +import Controller from "../src/Controller"; +import supertest from "supertest"; +import CsrfProtectionComponent from "../src/components/CsrfProtectionComponent"; +import UserPasswordComponent from "../src/auth/password/UserPasswordComponent"; +import {popEmail} from "./_mail_server"; +import AuthComponent from "../src/auth/AuthComponent"; +import Migration, {MigrationType} from "../src/db/Migration"; +import AddNameToUsersMigration from "../src/auth/migrations/AddNameToUsersMigration"; +import {followMagicLinkFromMail, testLogout} from "./_authentication_common"; +import UserEmail from "../src/auth/models/UserEmail"; + +let app: TestApp; +useApp(async (addr, port) => { + return app = new class extends TestApp { + protected async init(): Promise { + this.use(new class extends Controller { + public routes(): void { + this.get('/', (req, res) => { + res.render('home'); + }, 'home'); + this.get('/csrf', (req, res) => { + res.send(CsrfProtectionComponent.getCsrfToken(req.getSession())); + }, 'csrf'); + this.get('/is-auth', async (req, res) => { + const proofs = await this.getApp().as(AuthComponent).getAuthGuard().getProofs(req); + if (proofs.length > 0) res.sendStatus(200); + else res.sendStatus(401); + }, 'is-auth'); + } + }()); + + await super.init(); + } + + protected getMigrations(): MigrationType[] { + return super.getMigrations().filter(m => m !== AddNameToUsersMigration); + } + }(addr, port); +}); + +let agent: supertest.SuperTest; + +beforeAll(() => { + agent = supertest(app.getExpressApp()); +}); + +describe('Register with username and password (password)', () => { + test('Must be disabled', async () => { + const res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + // Register user + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'password', + identifier: 'entrapta', + password: 'darla_is_cute', + password_confirmation: 'darla_is_cute', + terms: 'on', + }) + .expect(500); + }); +}); + +describe('Register with email (magic_link)', () => { + test('General case', async () => { + const res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'glimmer@example.org', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + await testLogout(agent, cookies, csrf); + + // Verify saved user + const email = await UserEmail.select() + .with('user') + .where('email', 'glimmer@example.org') + .first(); + const user = email?.user.getOrFail(); + + expect(user).toBeDefined(); + + expect(email).toBeDefined(); + expect(email?.email).toStrictEqual('glimmer@example.org'); + + await expect(user?.as(UserPasswordComponent).verifyPassword('')).resolves.toStrictEqual(false); + }); + + test('Cannot register taken email', async () => { + const res = await agent.get('/csrf').expect(200); + const cookies = res.get('Set-Cookie'); + const csrf = res.text; + + await agent.post('/auth/register') + .set('Cookie', cookies) + .send({ + csrf: csrf, + auth_method: 'magic_link', + identifier: 'bow@example.org', + name: 'bow', + }) + .expect(302) + .expect('Location', '/magic/lobby?redirect_uri='); + + await followMagicLinkFromMail(agent, cookies); + + // Verify saved user + const userEmail = await UserEmail.select() + .with('user') + .where('email', 'bow@example.org') + .first(); + const user = userEmail?.user.getOrFail(); + + expect(user).toBeDefined(); + + // Attempt register with another mail but same username + const res2 = await agent.get('/csrf').expect(200); + + await agent.post('/auth/register') + .set('Cookie', res2.get('Set-Cookie')) + .send({ + csrf: res2.text, + auth_method: 'magic_link', + identifier: 'bow@example.org', + name: 'bow2', + }) + .expect(400); + + expect(await popEmail()).toBeNull(); + }); +}); diff --git a/test/CsrfProtectionComponent.test.ts b/test/CsrfProtectionComponent.test.ts new file mode 100644 index 0000000..f83a5cb --- /dev/null +++ b/test/CsrfProtectionComponent.test.ts @@ -0,0 +1,92 @@ +import useApp from "./_app"; +import Controller from "../src/Controller"; +import supertest from "supertest"; +import TestApp from "../src/TestApp"; +import CsrfProtectionComponent from "../src/components/CsrfProtectionComponent"; + +let app: TestApp; +useApp(async (addr, port) => { + return app = new class extends TestApp { + protected async init(): Promise { + this.use(new class extends Controller { + public routes(): void { + this.get('/', (req, res) => { + res.send(CsrfProtectionComponent.getCsrfToken(req.getSession())); + }, 'csrf_test'); + + this.post('/', (req, res) => { + res.json({ + status: 'ok', + }); + }, 'csrf_test'); + } + }()); + + await super.init(); + } + }(addr, port); +}); + +describe('Test CSRF protection', () => { + let cookies: string[]; + let csrf: string; + + test('no csrf token should be in session at first', (done) => { + const agent = supertest(app.getExpressApp()); + agent.post('/') + .expect(401) + .then(res => { + expect(res.text).toContain(`You weren't assigned any CSRF token.`); + cookies = res.get('Set-Cookie'); + + agent.get('/') + .set('Cookie', cookies) + .expect(200) + .then(res => { + csrf = res.text; + done(); + }).catch(done.fail); + }).catch(done.fail); + }); + + test('sending no csrf token should fail', (done) => { + expect(cookies).toBeDefined(); + + const agent = supertest(app.getExpressApp()); + agent.post('/') + .set('Cookie', cookies) + .expect(401) + .then((res) => { + expect(res.text).toContain(`You didn't provide any CSRF token.`); + done(); + }).catch(done.fail); + }); + + test('sending an invalid csrf token should fail', (done) => { + expect(cookies).toBeDefined(); + + const agent = supertest(app.getExpressApp()); + agent.post('/') + .set('Cookie', cookies) + .set('Content-Type', 'application/json') + .send({csrf: 'not_a_valid_csrf'}) + .expect(401) + .then(res => { + expect(res.text).toContain(`Tokens don't match.`); + done(); + }).catch(done.fail); + }); + + test('sending a valid csrf token should success', (done) => { + expect(cookies).toBeDefined(); + + const agent = supertest(app.getExpressApp()); + agent.post('/') + .set('Cookie', cookies) + .set('Content-Type', 'application/json') + .send({csrf: csrf}) + .expect(200) + .then(() => done()) + .catch(done.fail); + }); +}); diff --git a/test/Model.test.ts b/test/Model.test.ts index 2f488b5..8342ef5 100644 --- a/test/Model.test.ts +++ b/test/Model.test.ts @@ -1,40 +1,140 @@ import MysqlConnectionManager from "../src/db/MysqlConnectionManager"; import Model from "../src/db/Model"; -import Validator from "../src/db/Validator"; -import {MIGRATIONS} from "./_migrations"; +import ModelFactory from "../src/db/ModelFactory"; +import {ValidationBag} from "../src/db/Validator"; +import {logger} from "../src/Logger"; +import {ManyThroughModelRelation, OneModelRelation} from "../src/db/ModelRelation"; +import {MIGRATIONS} from "../src/TestApp"; +import config from "config"; class FakeDummyModel extends Model { - public name?: string; - public date?: Date; - public date_default?: Date; + public id?: number = undefined; + public name?: string = undefined; + public date?: Date = undefined; + public date_default?: Date = undefined; - protected defineProperties(): void { - this.defineProperty('name', new Validator().acceptUndefined().between(3, 256)); - this.defineProperty('date', new Validator()); - this.defineProperty('date_default', new Validator()); + protected init(): void { + this.setValidation('name').acceptUndefined().between(3, 256); } } -beforeAll(async (done) => { - MysqlConnectionManager.registerMigrations(MIGRATIONS); - await MysqlConnectionManager.prepare(); - done(); -}); +class Post extends Model { + public id?: number = undefined; + public author_id?: number = undefined; + public content?: string = undefined; -afterAll(async (done) => { - await MysqlConnectionManager.endPool(); - done(); -}); - -describe('Model', () => { - it('should have a proper table name', async () => { - expect(FakeDummyModel.table).toBe('fake_dummy_models'); - expect(new FakeDummyModel({}).table).toBe('fake_dummy_models'); + public readonly author = new OneModelRelation(this, Author, { + localKey: 'author_id', + foreignKey: 'id', }); - it('should insert and retrieve properly', async () => { - await MysqlConnectionManager.query(`DROP TABLE IF EXISTS ${FakeDummyModel.table}`); - await MysqlConnectionManager.query(`CREATE TABLE ${FakeDummyModel.table}( + protected init(): void { + this.setValidation('author_id').defined().exists(Author, 'id'); + } +} + +class Author extends Model { + public id?: number = undefined; + public name?: string = undefined; + + public readonly roles = new ManyThroughModelRelation(this, Role, { + localKey: 'id', + foreignKey: 'id', + pivotTable: 'author_role', + localPivotKey: 'author_id', + foreignPivotKey: 'role_id', + }); +} + +class Role extends Model { + public id?: number = undefined; + public name?: string = undefined; + + public readonly permissions = new ManyThroughModelRelation(this, Permission, { + localKey: 'id', + foreignKey: 'id', + pivotTable: 'role_permission', + localPivotKey: 'role_id', + foreignPivotKey: 'permission_id', + }); +} + +class Permission extends Model { + public id?: number = undefined; + public name?: string = undefined; +} + +class AuthorRole extends Model { + public static get table(): string { + return 'author_role'; + } + + public author_id?: number = undefined; + public role_id?: number = undefined; + + protected init(): void { + this.setValidation('author_id').defined().exists(Author, 'id'); + this.setValidation('role_id').defined().exists(Role, 'id'); + } +} + +class RolePermission extends Model { + public static get table(): string { + return 'role_permission'; + } + + public role_id?: number = undefined; + public permission_id?: number = undefined; + + protected init(): void { + this.setValidation('role_id').defined().exists(Role, 'id'); + this.setValidation('permission_id').defined().exists(Permission, 'id'); + } +} + +let fakeDummyModelModelFactory: ModelFactory; + +let postFactory: ModelFactory; +let authorFactory: ModelFactory; +let roleFactory: ModelFactory; +let permissionFactory: ModelFactory; + +beforeAll(async () => { + await MysqlConnectionManager.prepare(); + await MysqlConnectionManager.query('DROP DATABASE IF EXISTS ' + config.get('mysql.database')); + await MysqlConnectionManager.endPool(); + + logger.setSettings({minLevel: "trace"}); + MysqlConnectionManager.registerMigrations(MIGRATIONS); + ModelFactory.register(FakeDummyModel); + ModelFactory.register(Post); + ModelFactory.register(Author); + ModelFactory.register(Role); + ModelFactory.register(Permission); + ModelFactory.register(AuthorRole); + ModelFactory.register(RolePermission); + await MysqlConnectionManager.prepare(); + + // Create FakeDummyModel table + fakeDummyModelModelFactory = ModelFactory.get(FakeDummyModel); + postFactory = ModelFactory.get(Post); + authorFactory = ModelFactory.get(Author); + roleFactory = ModelFactory.get(Role); + permissionFactory = ModelFactory.get(Permission); + + await MysqlConnectionManager.query(`DROP TABLE IF EXISTS author_role`); + await MysqlConnectionManager.query(`DROP TABLE IF EXISTS role_permission`); + for (const factory of [ + fakeDummyModelModelFactory, + postFactory, + authorFactory, + roleFactory, + permissionFactory, + ]) { + await MysqlConnectionManager.query(`DROP TABLE IF EXISTS ${factory.table}`); + } + + await MysqlConnectionManager.query(`CREATE TABLE ${fakeDummyModelModelFactory.table}( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(256), date DATETIME, @@ -42,23 +142,255 @@ describe('Model', () => { PRIMARY KEY(id) )`); + await MysqlConnectionManager.query(`CREATE TABLE ${authorFactory.table}( + id INT NOT NULL AUTO_INCREMENT, + name VARCHAR(64), + PRIMARY KEY(id) + )`); + await MysqlConnectionManager.query(`CREATE TABLE ${postFactory.table}( + id INT NOT NULL AUTO_INCREMENT, + author_id INT NOT NULL, + content VARCHAR(512), + PRIMARY KEY(id), + FOREIGN KEY post_author_fk (author_id) REFERENCES ${authorFactory.table} (id) + )`); + await MysqlConnectionManager.query(`CREATE TABLE ${roleFactory.table}( + id INT NOT NULL AUTO_INCREMENT, + name VARCHAR(64), + PRIMARY KEY(id) + )`); + await MysqlConnectionManager.query(`CREATE TABLE ${permissionFactory.table}( + id INT NOT NULL AUTO_INCREMENT, + name VARCHAR(64), + PRIMARY KEY(id) + )`); + + await MysqlConnectionManager.query(`CREATE TABLE author_role( + id INT NOT NULL AUTO_INCREMENT, + author_id INT NOT NULL, + role_id INT NOT NULL, + PRIMARY KEY(id), + FOREIGN KEY author_role_author_fk (author_id) REFERENCES ${authorFactory.table} (id), + FOREIGN KEY author_role_role_fk (role_id) REFERENCES ${roleFactory.table} (id) + )`); + await MysqlConnectionManager.query(`CREATE TABLE role_permission( + id INT NOT NULL AUTO_INCREMENT, + role_id INT NOT NULL, + permission_id INT NOT NULL, + PRIMARY KEY(id), + FOREIGN KEY role_permission_role_fk (role_id) REFERENCES ${roleFactory.table} (id), + FOREIGN KEY role_permission_permission_fk (permission_id) REFERENCES ${permissionFactory.table} (id) + )`); + + + /// SEED /// + + // permissions + createPostPermission = Permission.create({name: 'create-post'}); + await createPostPermission.save(); + + moderatePostPermission = Permission.create({name: 'moderate-post'}); + await moderatePostPermission.save(); + + viewLogsPermission = Permission.create({name: 'view-logs'}); + await viewLogsPermission.save(); + + + // roles + guestRole = Role.create({name: 'guest'}); + await guestRole.save(); + await RolePermission.create({role_id: guestRole.id, permission_id: createPostPermission.id}).save(); + + moderatorRole = Role.create({name: 'moderator'}); + await moderatorRole.save(); + await RolePermission.create({role_id: moderatorRole.id, permission_id: createPostPermission.id}).save(); + await RolePermission.create({role_id: moderatorRole.id, permission_id: moderatePostPermission.id}).save(); + + adminRole = Role.create({name: 'admin'}); + await adminRole.save(); + await RolePermission.create({role_id: adminRole.id, permission_id: createPostPermission.id}).save(); + await RolePermission.create({role_id: adminRole.id, permission_id: moderatePostPermission.id}).save(); + await RolePermission.create({role_id: adminRole.id, permission_id: viewLogsPermission.id}).save(); + + + // authors + glimmerAuthor = Author.create({name: 'glimmer'}); + await glimmerAuthor.save(); + await AuthorRole.create({author_id: glimmerAuthor.id, role_id: guestRole.id}).save(); + + bowAuthor = Author.create({name: 'bow'}); + await bowAuthor.save(); + await AuthorRole.create({author_id: bowAuthor.id, role_id: moderatorRole.id}).save(); + + adoraAuthor = Author.create({name: 'adora'}); + await adoraAuthor.save(); + await AuthorRole.create({author_id: adoraAuthor.id, role_id: adminRole.id}).save(); + + + // posts + post1 = Post.create({author_id: glimmerAuthor.id, content: 'I\'m the queen now and you\'ll do as I order.'}); + await post1.save(); + + post2 = Post.create({author_id: adoraAuthor.id, content: 'But you\'re wrong!'}); + await post2.save(); + + post3 = Post.create({author_id: bowAuthor.id, content: 'Come on guys, let\'s talk this through.'}); + await post3.save(); +}); + +afterAll(async () => { + await MysqlConnectionManager.endPool(); +}); + +describe('Model', () => { + it('should construct properly', () => { + const date = new Date(888); + const model = fakeDummyModelModelFactory.create({ + name: 'a_name', + date: date, + non_existing_property: 'dropped_value', + }, true); + + expect(model.id).toBeUndefined(); + expect(model.name).toBe('a_name'); + expect(model.date).toBe(date); + expect(model.date_default).toBeUndefined(); + expect(model.non_existing_property).toBeUndefined(); + }); + + it('should have a proper table name', () => { + expect(fakeDummyModelModelFactory.table).toBe('fake_dummy_models'); + expect(FakeDummyModel.table).toBe('fake_dummy_models'); + expect(FakeDummyModel.create({}).table).toBe('fake_dummy_models'); + }); + + it('should insert properly', async () => { const date = new Date(569985); - let instance: FakeDummyModel | null = new FakeDummyModel({ + const insertInstance: FakeDummyModel | null = fakeDummyModelModelFactory.create({ name: 'name1', date: date, - }); + }, true); - await instance.save(); - expect(instance.id).toBe(1); - expect(instance.name).toBe('name1'); - expect(instance.date?.getTime()).toBeCloseTo(date.getTime(), -4); - expect(instance.date_default).toBeDefined(); - instance = await FakeDummyModel.getById(1); - expect(instance).toBeDefined(); - expect(instance!.id).toBe(1); - expect(instance!.name).toBe('name1'); - expect(instance!.date?.getTime()).toBeCloseTo(date.getTime(), -4); - expect(instance!.date_default).toBeDefined(); - }, 15000); -}); \ No newline at end of file + // Insert + expect(insertInstance.exists()).toBeFalsy(); + await insertInstance.save(); + expect(insertInstance.exists()).toBeTruthy(); + + expect(insertInstance.id).toBe(1); // Auto id from insert + expect(insertInstance.name).toBe('name1'); + expect(insertInstance.date?.getTime()).toBeCloseTo(date.getTime(), -4); + expect(insertInstance.date_default).toBeDefined(); + + // Check that row exists in DB + const retrievedInstance = await FakeDummyModel.getById(1); + expect(retrievedInstance).toBeDefined(); + expect(retrievedInstance?.id).toBe(1); + expect(retrievedInstance?.name).toBe('name1'); + expect(retrievedInstance?.date?.getTime()).toBeCloseTo(date.getTime(), -4); + expect(retrievedInstance?.date_default).toBeDefined(); + + const failingInsertModel = fakeDummyModelModelFactory.create({ + name: 'a', + }, true); + await expect(failingInsertModel.save()).rejects.toBeInstanceOf(ValidationBag); + }); + + it('should update properly', async () => { + const insertModel = fakeDummyModelModelFactory.create({ + name: 'update', + }, true); + await insertModel.save(); + + const preUpdatedModel = await FakeDummyModel.getById(insertModel.id); + expect(preUpdatedModel).not.toBeNull(); + expect(preUpdatedModel?.name).toBe(insertModel.name); + + // Update model + if (preUpdatedModel) { + preUpdatedModel.name = 'updated_name'; + await preUpdatedModel.save(); + } + + const postUpdatedModel = await FakeDummyModel.getById(insertModel.id); + expect(postUpdatedModel).not.toBeNull(); + expect(postUpdatedModel?.id).toBe(insertModel.id); + expect(postUpdatedModel?.name).not.toBe(insertModel.name); + expect(postUpdatedModel?.name).toBe(preUpdatedModel?.name); + }); + + it('should delete properly', async () => { + const insertModel = fakeDummyModelModelFactory.create({ + name: 'delete', + }, true); + await insertModel.save(); + + const preDeleteModel = await FakeDummyModel.getById(insertModel.id); + expect(preDeleteModel).not.toBeNull(); + + await preDeleteModel?.delete(); + + const postDeleteModel = await FakeDummyModel.getById(insertModel.id); + expect(postDeleteModel).toBeNull(); + }); +}); + +let createPostPermission: Permission; +let moderatePostPermission: Permission; +let viewLogsPermission: Permission; +let guestRole: Role; +let moderatorRole: Role; +let adminRole: Role; +let glimmerAuthor: Author; +let bowAuthor: Author; +let adoraAuthor: Author; +let post1: Post; +let post2: Post; +let post3: Post; + +describe('ModelRelation', () => { + test('Query and check relations', async () => { + const posts = await Post.select() + .with('author.roles.permissions') + .sortBy('id', 'ASC') + .get(); + + expect(posts.length).toBe(3); + + async function testPost( + post: Post, + originalPost: Post, + expectedAuthor: Author, + expectedRoles: Role[], + expectedPermissions: Permission[], + ) { + console.log('Testing post', post); + expect(post.id).toBe(originalPost.id); + expect(post.content).toBe(originalPost.content); + + const actualAuthor = await post.author.get(); + expect(actualAuthor).not.toBeNull(); + expect(await post.author.has(expectedAuthor)).toBeTruthy(); + expect(actualAuthor?.equals(expectedAuthor)).toBe(true); + + const authorRoles = await actualAuthor?.roles.get() || []; + console.log('Roles:'); + expect(authorRoles.map(r => r.id)).toStrictEqual(expectedRoles.map(r => r.id)); + + const authorPermissions = (await Promise.all(authorRoles.map(async r => await r.permissions.get()))) + .flatMap(p => p); + console.log('Permissions:'); + expect(authorPermissions.map(p => p.id)).toStrictEqual(expectedPermissions.map(p => p.id)); + } + + await testPost(posts[0], post1, glimmerAuthor, + [guestRole], + [createPostPermission]); + await testPost(posts[1], post2, adoraAuthor, + [adminRole], + [createPostPermission, moderatePostPermission, viewLogsPermission]); + await testPost(posts[2], post3, bowAuthor, + [moderatorRole], + [createPostPermission, moderatePostPermission]); + }); +}); diff --git a/test/ModelQuery.test.ts b/test/ModelQuery.test.ts new file mode 100644 index 0000000..92bc7df --- /dev/null +++ b/test/ModelQuery.test.ts @@ -0,0 +1,126 @@ +import ModelQuery, {SelectFieldValue, WhereOperator} from "../src/db/ModelQuery"; +import ModelFactory from "../src/db/ModelFactory"; +import Model from "../src/db/Model"; + +describe('Test ModelQuery', () => { + test('select', () => { + const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory, 'f1', '"Test" as f2') + .where('f4', 'v4') + .where('f5', true) + .where('f6', null) + .where('f7', undefined); + expect(query.toString(true)).toBe('SELECT `model`.`f1`,"Test" as f2 FROM `model` WHERE `f4`=? AND `f5`=true AND `f6` IS null AND `f7` IS null'); + expect(query.variables).toStrictEqual(['v4']); + }); + + test('order by', () => { + const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory) + .sortBy('model.f2', 'ASC'); + expect(query.toString(true)).toBe('SELECT `model`.* FROM `model` ORDER BY `model`.`f2` ASC'); + + const queryRaw = ModelQuery.select({table: 'model'} as unknown as ModelFactory) + .sortBy('coalesce(model.f1, model.f2)', 'ASC', true); + expect(queryRaw.toString(true)).toBe('SELECT `model`.* FROM `model` ORDER BY coalesce(model.f1, model.f2) ASC'); + }); + + test('create (insert into)', () => { + const date = new Date(); + const query = ModelQuery.insert( + {table: 'model'} as unknown as ModelFactory, + { + 'boolean': true, + 'null': null, + 'undefined': undefined, + 'string': 'string', + 'date': date, + 'sensitive': 'sensitive', // Reserved word + }, + ); + expect(query.toString(true)).toBe('INSERT INTO `model` (`boolean`,`null`,`undefined`,`string`,`date`,`sensitive`) VALUES(true,null,null,?,?,?)'); + expect(query.variables).toStrictEqual([ + 'string', + date, + 'sensitive', + ]); + }); + + test('update', () => { + const date = new Date(); + const query = ModelQuery.update({table: 'model'} as unknown as ModelFactory, { + 'boolean': true, + 'null': null, + 'undefined': undefined, + 'string': 'string', + 'date': date, + 'sensitive': 'sensitive', // Reserved word + }).where('f4', 'v4') + .where('f5', true) + .where('f6', null) + .where('f7', undefined); + expect(query.toString(true)).toBe('UPDATE `model` SET `model`.`boolean`=true,`model`.`null`=null,`model`.`undefined`=null,`model`.`string`=?,`model`.`date`=?,`model`.`sensitive`=? WHERE `f4`=? AND `f5`=true AND `f6` IS null AND `f7` IS null'); + expect(query.variables).toStrictEqual([ + 'string', + date, + 'sensitive', + 'v4', + ]); + }); + + test('function select', () => { + const query = ModelQuery.select( + {table: 'model'} as unknown as ModelFactory, + 'f1', + new SelectFieldValue('_count', 'COUNT(*)', true), + ); + expect(query.toString(true)).toBe('SELECT `model`.`f1`,(COUNT(*)) AS `_count` FROM `model`'); + expect(query.variables).toStrictEqual([]); + }); + + test('pivot', () => { + const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory, 'f1'); + query.pivot('pivot.f2', 'f3'); + + expect(query.toString(true)).toBe('SELECT `model`.`f1`,`pivot`.`f2`,`model`.`f3` FROM `model`'); + expect(query.variables).toStrictEqual([]); + }); + + test('groupWhere generates proper query', () => { + const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory, '*'); + query.where('f1', 'v1'); + query.groupWhere(q => q.where('f2', 'v2').where('f3', 'v3') + .groupWhere(q => q.where('f4', 'v4'), WhereOperator.OR)) + .where('f5', 'v5'); + + expect(query.toString(true)).toBe('SELECT `model`.* FROM `model` WHERE `f1`=? AND (`f2`=? AND `f3`=? OR (`f4`=?)) AND `f5`=?'); + expect(query.variables).toStrictEqual(['v1', 'v2', 'v3', 'v4', 'v5']); + }); + + test('recursive queries', () => { + const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory, '*'); + query.where('f1', 'v1'); + query.leftJoin('test').on('model.j1', 'test.j2'); + query.recursive({localKey: 'local', foreignKey: 'foreign'}, false); + query.limit(8); + + expect(query.toString(true)).toBe("WITH RECURSIVE cte AS (SELECT `model`.*,1 AS __depth, CONCAT(`local`) AS __path FROM `model` WHERE `f1`=? UNION SELECT o.*,c.__depth + 1,CONCAT(c.__path,'/',o.`local`) AS __path FROM `model` AS o, cte AS c WHERE o.`foreign`=c.`local`) SELECT * FROM cte LEFT JOIN `test` ON `model`.`j1`=`test`.`j2` ORDER BY __path ASC LIMIT 8"); + expect(query.variables).toStrictEqual(['v1']); + + const reversedQuery = ModelQuery.select({table: 'model'} as unknown as ModelFactory, '*'); + reversedQuery.where('f1', 'v1'); + reversedQuery.leftJoin('test').on('model.j1', 'test.j2'); + reversedQuery.recursive({localKey: 'local', foreignKey: 'foreign'}, true); + + expect(reversedQuery.toString(true)).toBe("WITH RECURSIVE cte AS (SELECT `model`.*,1 AS __depth, CONCAT(`foreign`) AS __path FROM `model` WHERE `f1`=? UNION SELECT o.*,c.__depth + 1,CONCAT(c.__path,'/',o.`foreign`) AS __path FROM `model` AS o, cte AS c WHERE o.`foreign`=c.`local`) SELECT * FROM cte LEFT JOIN `test` ON `model`.`j1`=`test`.`j2` ORDER BY __path DESC"); + expect(reversedQuery.variables).toStrictEqual(['v1']); + }); + + test('union queries', () => { + const query = ModelQuery.select({table: 'model'} as unknown as ModelFactory, '*'); + const query2 = ModelQuery.select({table: 'model2'} as unknown as ModelFactory, '*'); + query2.where('f2', 'v2'); + query.union(query2, 'model.f1', 'DESC', false, 8); + + expect(query.toString(true)).toBe("(SELECT `model`.* FROM `model`) UNION (SELECT `model2`.* FROM `model2` WHERE `f2`=?) ORDER BY `model`.`f1` DESC LIMIT 8"); + expect(query.variables).toStrictEqual(['v2']); + }); +}); diff --git a/test/_app.ts b/test/_app.ts new file mode 100644 index 0000000..643d66d --- /dev/null +++ b/test/_app.ts @@ -0,0 +1,41 @@ +import Application from "../src/Application"; +import {setupMailServer, teardownMailServer} from "./_mail_server"; +import TestApp from "../src/TestApp"; +import MysqlConnectionManager from "../src/db/MysqlConnectionManager"; +import config from "config"; + + +export default function useApp(appSupplier?: (addr: string, port: number) => Promise): void { + let app: Application; + + beforeAll(async (done) => { + await MysqlConnectionManager.prepare(); + await MysqlConnectionManager.query('DROP DATABASE IF EXISTS ' + config.get('mysql.database')); + await MysqlConnectionManager.endPool(); + + await setupMailServer(); + app = appSupplier ? await appSupplier('127.0.0.1', 8966) : new TestApp('127.0.0.1', 8966); + + await app.start(); + done(); + }); + + afterAll(async (done) => { + const errors = []; + + try { + await app.stop(); + } catch (e) { + errors.push(e); + } + + try { + await teardownMailServer(); + } catch (e) { + errors.push(e); + } + + if (errors.length > 0) throw errors; + done(); + }); +} diff --git a/test/_authentication_common.ts b/test/_authentication_common.ts new file mode 100644 index 0000000..a0d9c2b --- /dev/null +++ b/test/_authentication_common.ts @@ -0,0 +1,39 @@ +import {popEmail} from "./_mail_server"; +import supertest from "supertest"; + +export async function followMagicLinkFromMail( + agent: supertest.SuperTest, + cookies: string[], + expectedRedirectUrl: string = '/', +): Promise { + const mail: Record | null = await popEmail(); + expect(mail).not.toBeNull(); + + const query = (mail?.text as string).split('/magic/link?')[1].split('\n')[0]; + expect(query).toBeDefined(); + + await agent.get('/magic/link?' + query) + .expect(200); + await agent.get('/magic/lobby') + .set('Cookie', cookies) + .expect(302) + .expect('Location', expectedRedirectUrl); +} + +export async function testLogout( + agent: supertest.SuperTest, + cookies: string[], + csrf: string, +): Promise { + // Authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(200); + + // Logout + await agent.post('/auth/logout') + .set('Cookie', cookies) + .send({csrf: csrf}) + .expect(302); + + // Not authenticated + await agent.get('/is-auth').set('Cookie', cookies).expect(401); +} diff --git a/test/_mail_server.ts b/test/_mail_server.ts new file mode 100644 index 0000000..5761401 --- /dev/null +++ b/test/_mail_server.ts @@ -0,0 +1,38 @@ +import MailDev, {Mail} from "maildev"; + +export const MAIL_SERVER = new MailDev({ + ip: 'localhost', +}); + +export async function setupMailServer(): Promise { + await new Promise((resolve, reject) => MAIL_SERVER.listen((err?: Error) => { + if (err) reject(err); + else resolve(); + })); +} + +export async function teardownMailServer(): Promise { + await new Promise((resolve, reject) => MAIL_SERVER.close((err?: Error) => { + if (err) reject(err); + else resolve(); + })); +} + +export async function popEmail(): Promise | null> { + return await new Promise | null>((resolve, reject) => { + MAIL_SERVER.getAllEmail((err: Error | undefined, emails: Mail[]) => { + if (err) return reject(err); + if (emails.length === 0) return resolve(null); + const email = emails[0]; + + expect(email).toBeDefined(); + expect(email.id).toBeDefined(); + return resolve(new Promise>((resolve, reject) => { + MAIL_SERVER.deleteEmail(email.id as string, (err: Error | undefined) => { + if (err) return reject(err); + resolve(email as Record); + }); + })); + }); + }); +} diff --git a/test/_migrations.ts b/test/_migrations.ts deleted file mode 100644 index 020829c..0000000 --- a/test/_migrations.ts +++ /dev/null @@ -1,7 +0,0 @@ -import CreateMigrationsTable from "../src/migrations/CreateMigrationsTable"; -import CreateLogsTable from "../src/migrations/CreateLogsTable"; - -export const MIGRATIONS = [ - CreateMigrationsTable, - CreateLogsTable, -]; \ No newline at end of file diff --git a/test/types/maildev.d.ts b/test/types/maildev.d.ts new file mode 100644 index 0000000..05570f3 --- /dev/null +++ b/test/types/maildev.d.ts @@ -0,0 +1,216 @@ +// Type definitions for maildev 1.0.0-rc3 +// Project: https://github.com/djfarrelly/maildev +// Definitions by: Cyril Schumacher +// Zak Barbuto +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/// + +declare module 'maildev' { + import fs = require("fs"); + + /** + * Interface for {@link MailDev}. + */ + export default class MailDev { + /** + * Constructor. + * + * @public + * @param {MailDevOptions} options The options. + */ + public constructor(options: MailDevOptions); + + /** + * Deletes a given email by identifier. + * + * @public + * @param {string} id The email identifier. + * @param {Function} callback The error callback. + */ + public deleteEmail(id: string, callback?: (error: Error) => void): void; + + /** + * Deletes all email and their attachments. + * + * @public + * @param {Function} callback The error callback. + */ + public deleteAllEmail(callback?: (error: Error) => void): void; + + /** + * Stops the SMTP server. + * + * @public + * @param {Function} callback The error callback. + */ + public close(callback?: (error: Error) => void): void; + + /** + * Accepts e-mail identifier, returns email object. + * + * @public + * @param {string} id The e-mail identifier. + * @param {Function} callback The error callback. + */ + public getEmail(id: string, callback?: (error: Error) => void): void; + + /** + * Returns a readable stream of the raw e-mail. + * + * @public + * @param {string} id The e-mail identifier. + */ + public getRawEmail(id: string, callback?: (error: Error, readStream: fs.ReadStream) => void): void; + + /** + * Returns array of all e-mail. + + * @public + */ + public getAllEmail(done: (error: Error, emails: Array>) => void): void; + + /** + * Starts the SMTP server. + * + * @public + * @param {Function} callback The error callback. + */ + public listen(callback?: (error: Error) => void): void; + + /** + * Event called when a new e-mail is received. Callback receives single mail object. + * + * @public + * @param {string} eventName The event name. + * @param {Function} email The email. + */ + public on(eventName: string, callback: (email: Record) => void): void; + + /** + * Relay the e-mail. + * + * @param {string} idOrMailObject The identifier or mail object. + * @param {Function} done The callback. + */ + public relayMail(idOrMailObject: string, done: (error: Error) => void): void; + } + + /** + * Interface for {@link MailDev} options. + */ + export interface MailDevOptions { + /** + * IP Address to bind SMTP service to', '0.0.0.0' + * + * @type {string} + */ + ip?: string; + + /** + * SMTP host for outgoing emails + * + * @type {string} + */ + outgoingHost?: string; + + /** + * SMTP password for outgoing emails + * + * @type {string} + */ + outgoingPass?: string; + + /** + * SMTP port for outgoing emails. + * + * @type {number} + */ + outgoingPort?: number; + + /** + * SMTP user for outgoing emails + * + * @type {string} + */ + outgoingUser?: string; + + /** + * Use SMTP SSL for outgoing emails + * + * @type {boolean} + */ + outgoingSecure?: boolean; + + /** + * SMTP port to catch emails. + * + * @type {number} + */ + smtp?: number; + + /** + * Port to use for web UI + * + * @type {number} + */ + web?: number; + + /** + * IP Address to bind HTTP service to + * + * @type {string} + */ + webIp?: string; + + /** + * Do not start web UI + * + * @type {boolean} + */ + disableWeb?: boolean; + + /** + * Do not output console.log messages + * + * @type {boolean} + */ + silent?: boolean; + + /** + * HTTP user for GUI + * + * @type {string} + */ + webUser?: string; + + /** + * HTTP password for GUI + * + * @type {string} + */ + webPass?: string; + + /** + * Open the Web GUI after startup + * + * @type {boolean} + */ + open?: boolean; + } + + /** + * Interface for mail. + */ + export interface Mail { + /** + * Identifier. + */ + id?: string; + + /** + * Client. + */ + envelope?: Record; + } +} diff --git a/test/views/home.njk b/test/views/home.njk new file mode 100644 index 0000000..498d4f4 --- /dev/null +++ b/test/views/home.njk @@ -0,0 +1,7 @@ +{% extends 'layouts/base.njk' %} + +{% set title = app.name + ' - Home' %} + +{% block body %} +

{{ title }}

+{% endblock %} diff --git a/test/views/layouts/base.njk b/test/views/layouts/base.njk new file mode 100644 index 0000000..a3b9693 --- /dev/null +++ b/test/views/layouts/base.njk @@ -0,0 +1,59 @@ +{% extends 'layouts/barebone.njk' %} +{% import 'macros.njk' as macros %} + +{% block _stylesheets %} + {{ super() }} + + {% block stylesheets %}{% endblock %} +{% endblock %} +{% block _scripts %} + {{ super() }} + {% block scripts %}{% endblock %} +{% endblock %} + +{% block header %} + + +{% endblock %} + +{% block _body %} +
+ {{ macros.messages(flash) }} +
+ +
+ {% if h1 %} +

{{ h1 }}

+ {% endif %} + {% if subtitle %} +

{{ subtitle }}

+ {% endif %} + + {% block body %}{% endblock %} +
+{% endblock %} + +{% block footer %}{{ app.name }} v{{ app_version }} - all rights reserved.{% endblock %} diff --git a/test/views/test/throws_error.njk b/test/views/test/throws_error.njk new file mode 100644 index 0000000..6106ee8 --- /dev/null +++ b/test/views/test/throws_error.njk @@ -0,0 +1,3 @@ +{{ route('non-existing-fake-route') }} + +This should never be distributed. \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 2b8a001..f34d0e9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,8 +6,6 @@ "stripInternal": true, "strict": true, - // "noUnusedLocals": true, - // "noUnusedParameters": true, "allowSyntheticDefaultImports": true, "moduleResolution": "Node", @@ -28,10 +26,10 @@ ], "lib": [ "es2020" - ] + ], + "resolveJsonModule": true }, "include": [ - "src/**/*", - "config/*" + "src/**/*" ] } \ No newline at end of file diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000..897a6b4 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "typeRoots": [ + "node_modules/@types", + "src/types", + "test/types" + ] + }, + "include": [ + "src/types/**/*", + "test/**/*" + ] +} \ No newline at end of file diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo deleted file mode 100644 index acc04c6..0000000 --- a/tsconfig.tsbuildinfo +++ /dev/null @@ -1,3132 +0,0 @@ -{ - "program": { - "fileInfos": { - "./node_modules/typescript/lib/lib.es5.d.ts": { - "version": "b42eddba1a53c9d27279cfe7fc0416c10a81489826ad47e39013b9d340fc0cc7", - "signature": "b42eddba1a53c9d27279cfe7fc0416c10a81489826ad47e39013b9d340fc0cc7" - }, - "./node_modules/typescript/lib/lib.es2015.d.ts": { - "version": "7994d44005046d1413ea31d046577cdda33b8b2470f30281fd9c8b3c99fe2d96", - "signature": "7994d44005046d1413ea31d046577cdda33b8b2470f30281fd9c8b3c99fe2d96" - }, - "./node_modules/typescript/lib/lib.es2016.d.ts": { - "version": "5f217838d25704474d9ef93774f04164889169ca31475fe423a9de6758f058d1", - "signature": "5f217838d25704474d9ef93774f04164889169ca31475fe423a9de6758f058d1" - }, - "./node_modules/typescript/lib/lib.es2017.d.ts": { - "version": "459097c7bdd88fc5731367e56591e4f465f2c9de81a35427a7bd473165c34743", - "signature": "459097c7bdd88fc5731367e56591e4f465f2c9de81a35427a7bd473165c34743" - }, - "./node_modules/typescript/lib/lib.es2018.d.ts": { - "version": "9c67dcc7ca897b61f58d57d487bc9f07950546e5ac8701cbc41a8a4fec48b091", - "signature": "9c67dcc7ca897b61f58d57d487bc9f07950546e5ac8701cbc41a8a4fec48b091" - }, - "./node_modules/typescript/lib/lib.es2019.d.ts": { - "version": "0fc0f68d3f4d94aa65fab955592e4a9f2066e6f8ee2f66fcc45adf4037fc167b", - "signature": "0fc0f68d3f4d94aa65fab955592e4a9f2066e6f8ee2f66fcc45adf4037fc167b" - }, - "./node_modules/typescript/lib/lib.es2020.d.ts": { - "version": "585694acba05fe18d6ad9c9f662f3de3766779933efb9f2d8c482c1a92bf073c", - "signature": "585694acba05fe18d6ad9c9f662f3de3766779933efb9f2d8c482c1a92bf073c" - }, - "./node_modules/typescript/lib/lib.es2015.core.d.ts": { - "version": "734ddc145e147fbcd55f07d034f50ccff1086f5a880107665ec326fb368876f6", - "signature": "734ddc145e147fbcd55f07d034f50ccff1086f5a880107665ec326fb368876f6" - }, - "./node_modules/typescript/lib/lib.es2015.collection.d.ts": { - "version": "4a0862a21f4700de873db3b916f70e41570e2f558da77d2087c9490f5a0615d8", - "signature": "4a0862a21f4700de873db3b916f70e41570e2f558da77d2087c9490f5a0615d8" - }, - "./node_modules/typescript/lib/lib.es2015.generator.d.ts": { - "version": "765e0e9c9d74cf4d031ca8b0bdb269a853e7d81eda6354c8510218d03db12122", - "signature": "765e0e9c9d74cf4d031ca8b0bdb269a853e7d81eda6354c8510218d03db12122" - }, - "./node_modules/typescript/lib/lib.es2015.iterable.d.ts": { - "version": "285958e7699f1babd76d595830207f18d719662a0c30fac7baca7df7162a9210", - "signature": "285958e7699f1babd76d595830207f18d719662a0c30fac7baca7df7162a9210" - }, - "./node_modules/typescript/lib/lib.es2015.promise.d.ts": { - "version": "d4deaafbb18680e3143e8b471acd650ed6f72a408a33137f0a0dd104fbe7f8ca", - "signature": "d4deaafbb18680e3143e8b471acd650ed6f72a408a33137f0a0dd104fbe7f8ca" - }, - "./node_modules/typescript/lib/lib.es2015.proxy.d.ts": { - "version": "5e72f949a89717db444e3bd9433468890068bb21a5638d8ab15a1359e05e54fe", - "signature": "5e72f949a89717db444e3bd9433468890068bb21a5638d8ab15a1359e05e54fe" - }, - "./node_modules/typescript/lib/lib.es2015.reflect.d.ts": { - "version": "f5b242136ae9bfb1cc99a5971cccc44e99947ae6b5ef6fd8aa54b5ade553b976", - "signature": "f5b242136ae9bfb1cc99a5971cccc44e99947ae6b5ef6fd8aa54b5ade553b976" - }, - "./node_modules/typescript/lib/lib.es2015.symbol.d.ts": { - "version": "9ae2860252d6b5f16e2026d8a2c2069db7b2a3295e98b6031d01337b96437230", - "signature": "9ae2860252d6b5f16e2026d8a2c2069db7b2a3295e98b6031d01337b96437230" - }, - "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts": { - "version": "3e0a459888f32b42138d5a39f706ff2d55d500ab1031e0988b5568b0f67c2303", - "signature": "3e0a459888f32b42138d5a39f706ff2d55d500ab1031e0988b5568b0f67c2303" - }, - "./node_modules/typescript/lib/lib.es2016.array.include.d.ts": { - "version": "3f96f1e570aedbd97bf818c246727151e873125d0512e4ae904330286c721bc0", - "signature": "3f96f1e570aedbd97bf818c246727151e873125d0512e4ae904330286c721bc0" - }, - "./node_modules/typescript/lib/lib.es2017.object.d.ts": { - "version": "c2d60b2e558d44384e4704b00e6b3d154334721a911f094d3133c35f0917b408", - "signature": "c2d60b2e558d44384e4704b00e6b3d154334721a911f094d3133c35f0917b408" - }, - "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts": { - "version": "b8667586a618c5cf64523d4e500ae39e781428abfb28f3de441fc66b56144b6f", - "signature": "b8667586a618c5cf64523d4e500ae39e781428abfb28f3de441fc66b56144b6f" - }, - "./node_modules/typescript/lib/lib.es2017.string.d.ts": { - "version": "21df2e0059f14dcb4c3a0e125859f6b6ff01332ee24b0065a741d121250bc71c", - "signature": "21df2e0059f14dcb4c3a0e125859f6b6ff01332ee24b0065a741d121250bc71c" - }, - "./node_modules/typescript/lib/lib.es2017.intl.d.ts": { - "version": "c1759cb171c7619af0d2234f2f8fb2a871ee88e956e2ed91bb61778e41f272c6", - "signature": "c1759cb171c7619af0d2234f2f8fb2a871ee88e956e2ed91bb61778e41f272c6" - }, - "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts": { - "version": "28569d59e07d4378cb3d54979c4c60f9f06305c9bb6999ffe6cab758957adc46", - "signature": "28569d59e07d4378cb3d54979c4c60f9f06305c9bb6999ffe6cab758957adc46" - }, - "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts": { - "version": "2958de3d25bfb0b5cdace0244e11c9637e5988920b99024db705a720ce6348e7", - "signature": "2958de3d25bfb0b5cdace0244e11c9637e5988920b99024db705a720ce6348e7" - }, - "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts": { - "version": "85085a0783532dc04b66894748dc4a49983b2fbccb0679b81356947021d7a215", - "signature": "85085a0783532dc04b66894748dc4a49983b2fbccb0679b81356947021d7a215" - }, - "./node_modules/typescript/lib/lib.es2018.intl.d.ts": { - "version": "5494f46d3a8a0329d13ddc37f8759d5288760febb51c92336608d1c06bb18d29", - "signature": "5494f46d3a8a0329d13ddc37f8759d5288760febb51c92336608d1c06bb18d29" - }, - "./node_modules/typescript/lib/lib.es2018.promise.d.ts": { - "version": "efe049114bad1035b0aa9a4a0359f50ab776e3897c411521e51d3013079cbd62", - "signature": "efe049114bad1035b0aa9a4a0359f50ab776e3897c411521e51d3013079cbd62" - }, - "./node_modules/typescript/lib/lib.es2018.regexp.d.ts": { - "version": "e7780d04cd4120ee554c665829db2bbdd6b947cbaa3c150b7d9ea74df3beb2e8", - "signature": "e7780d04cd4120ee554c665829db2bbdd6b947cbaa3c150b7d9ea74df3beb2e8" - }, - "./node_modules/typescript/lib/lib.es2019.array.d.ts": { - "version": "7054111c49ea06f0f2e623eab292a9c1ae9b7d04854bd546b78f2b8b57e13d13", - "signature": "7054111c49ea06f0f2e623eab292a9c1ae9b7d04854bd546b78f2b8b57e13d13" - }, - "./node_modules/typescript/lib/lib.es2019.object.d.ts": { - "version": "989b95205f1189943fab0ce12a39c80570edf8f200aca60e0fdc500afc4d5859", - "signature": "989b95205f1189943fab0ce12a39c80570edf8f200aca60e0fdc500afc4d5859" - }, - "./node_modules/typescript/lib/lib.es2019.string.d.ts": { - "version": "e9bfd234b801c955459cde7109bebf6fd1b4814fd8b394942f5ba746828a6486", - "signature": "e9bfd234b801c955459cde7109bebf6fd1b4814fd8b394942f5ba746828a6486" - }, - "./node_modules/typescript/lib/lib.es2019.symbol.d.ts": { - "version": "5f2a476cdb4990b249077b46a6242979876e9bba5152e066d68fad77510ee328", - "signature": "5f2a476cdb4990b249077b46a6242979876e9bba5152e066d68fad77510ee328" - }, - "./node_modules/typescript/lib/lib.es2020.bigint.d.ts": { - "version": "0c9ea8c2028047f39a3f66752682604f543c08be8806258c3d95c93e75a43255", - "signature": "0c9ea8c2028047f39a3f66752682604f543c08be8806258c3d95c93e75a43255" - }, - "./node_modules/typescript/lib/lib.es2020.promise.d.ts": { - "version": "4a44be5b17ae6385fcc9a486361f50231992d556c9298373ae0d38cfae9f4056", - "signature": "4a44be5b17ae6385fcc9a486361f50231992d556c9298373ae0d38cfae9f4056" - }, - "./node_modules/typescript/lib/lib.es2020.string.d.ts": { - "version": "01f1170ac78a31964a8a05cc46df7dc63d6911f683cb49586b27c49f54187a86", - "signature": "01f1170ac78a31964a8a05cc46df7dc63d6911f683cb49586b27c49f54187a86" - }, - "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts": { - "version": "1debec13dc47b66e7e5a5ceb3872ea7f141613148f6083ef6dc38626ee8c9a93", - "signature": "1debec13dc47b66e7e5a5ceb3872ea7f141613148f6083ef6dc38626ee8c9a93" - }, - "./node_modules/typescript/lib/lib.esnext.intl.d.ts": { - "version": "1377923021927244ea19433873b997ad8585533b0a56d5de29cda497f7842756", - "signature": "1377923021927244ea19433873b997ad8585533b0a56d5de29cda497f7842756" - }, - "./node_modules/@types/node/globals.d.ts": { - "version": "9d0b32c595a2e0d320a56b3d0e8f0a317e4149239ec913aa8f11eeb73edc92be", - "signature": "9d0b32c595a2e0d320a56b3d0e8f0a317e4149239ec913aa8f11eeb73edc92be" - }, - "./node_modules/@types/node/async_hooks.d.ts": { - "version": "96e547b51f95ee76bdb25731c92420fa6f93b59c3f38f23d505be36e2de394ee", - "signature": "96e547b51f95ee76bdb25731c92420fa6f93b59c3f38f23d505be36e2de394ee" - }, - "./node_modules/@types/node/buffer.d.ts": { - "version": "61215c1a376bbe8f51cab4cc4ddbf3746387015113c37a84d981d4738c21b878", - "signature": "61215c1a376bbe8f51cab4cc4ddbf3746387015113c37a84d981d4738c21b878" - }, - "../node_modules/@types/events/index.d.ts": { - "version": "400db42c3a46984118bff14260d60cec580057dc1ab4c2d7310beb643e4f5935", - "signature": "400db42c3a46984118bff14260d60cec580057dc1ab4c2d7310beb643e4f5935" - }, - "./node_modules/@types/node/child_process.d.ts": { - "version": "3ca89ecb953fe3b63dae41e5bb986506e812754dde0369c5fe61de26eff47dbe", - "signature": "3ca89ecb953fe3b63dae41e5bb986506e812754dde0369c5fe61de26eff47dbe" - }, - "./node_modules/@types/node/cluster.d.ts": { - "version": "123ec69e4b3a686eb49afd94ebe3292a5c84a867ecbcb6bb84bdd720a12af803", - "signature": "123ec69e4b3a686eb49afd94ebe3292a5c84a867ecbcb6bb84bdd720a12af803" - }, - "./node_modules/@types/node/console.d.ts": { - "version": "525c8fc510d9632d2a0a9de2d41c3ac1cdd79ff44d3b45c6d81cacabb683528d", - "signature": "525c8fc510d9632d2a0a9de2d41c3ac1cdd79ff44d3b45c6d81cacabb683528d" - }, - "./node_modules/@types/node/constants.d.ts": { - "version": "90c85ddbb8de82cd19198bda062065fc51b7407c0f206f2e399e65a52e979720", - "signature": "90c85ddbb8de82cd19198bda062065fc51b7407c0f206f2e399e65a52e979720" - }, - "./node_modules/@types/node/crypto.d.ts": { - "version": "d56c93b6bf66e602869e926ddc8b1b4630d1ff397909291767d18d4ffc22d33f", - "signature": "d56c93b6bf66e602869e926ddc8b1b4630d1ff397909291767d18d4ffc22d33f" - }, - "./node_modules/@types/node/dgram.d.ts": { - "version": "7ecfe97b43aa6c8b8f90caa599d5648bb559962e74e6f038f73a77320569dd78", - "signature": "7ecfe97b43aa6c8b8f90caa599d5648bb559962e74e6f038f73a77320569dd78" - }, - "./node_modules/@types/node/dns.d.ts": { - "version": "aad3237c3f99480041cad7ca04d64307c98933996f822342b7c0ee4a78553346", - "signature": "aad3237c3f99480041cad7ca04d64307c98933996f822342b7c0ee4a78553346" - }, - "./node_modules/@types/node/domain.d.ts": { - "version": "4d4c83f77ac21a72252785baa5328a5612b0b6598d512f68b8cb14f7966d059e", - "signature": "4d4c83f77ac21a72252785baa5328a5612b0b6598d512f68b8cb14f7966d059e" - }, - "./node_modules/@types/node/events.d.ts": { - "version": "5ffa4219ee64e130980a4231392cbc628544df137ccf650ae8d76e0a1744fd2b", - "signature": "5ffa4219ee64e130980a4231392cbc628544df137ccf650ae8d76e0a1744fd2b" - }, - "./node_modules/@types/node/fs.d.ts": { - "version": "e1a12c7e7951b9762cfbcc43c72eb5611120967706a7c3142ad303c6b7ee767f", - "signature": "e1a12c7e7951b9762cfbcc43c72eb5611120967706a7c3142ad303c6b7ee767f" - }, - "./node_modules/@types/node/http.d.ts": { - "version": "b5fd0a137bd6d0afe291d465e99c7469b082b66b3ee89273b3b22801b6c2948e", - "signature": "b5fd0a137bd6d0afe291d465e99c7469b082b66b3ee89273b3b22801b6c2948e" - }, - "./node_modules/@types/node/http2.d.ts": { - "version": "873da589b78a1f1fa7d623483bd2c2730a02e0852259fb8fdcfe5221ac51d18a", - "signature": "873da589b78a1f1fa7d623483bd2c2730a02e0852259fb8fdcfe5221ac51d18a" - }, - "./node_modules/@types/node/https.d.ts": { - "version": "c969bf4c7cdfe4d5dd28aa09432f99d09ad1d8d8b839959646579521d0467d1a", - "signature": "c969bf4c7cdfe4d5dd28aa09432f99d09ad1d8d8b839959646579521d0467d1a" - }, - "./node_modules/@types/node/inspector.d.ts": { - "version": "4218ced3933a31eed1278d350dd63c5900df0f0904f57d61c054d7a4b83dbe4c", - "signature": "4218ced3933a31eed1278d350dd63c5900df0f0904f57d61c054d7a4b83dbe4c" - }, - "./node_modules/@types/node/module.d.ts": { - "version": "a376e245f494b58365a4391a2568e6dd9da372c3453f4732eb6e15ebb9038451", - "signature": "a376e245f494b58365a4391a2568e6dd9da372c3453f4732eb6e15ebb9038451" - }, - "./node_modules/@types/node/net.d.ts": { - "version": "ffe8912b7c45288810c870b768190c6c097459930a587dd6ef0d900a5529a811", - "signature": "ffe8912b7c45288810c870b768190c6c097459930a587dd6ef0d900a5529a811" - }, - "./node_modules/@types/node/os.d.ts": { - "version": "f53678bdb9f25445c8cdf021f2b003b74fd638e69bb1959dde8e370e8cc1e4fa", - "signature": "f53678bdb9f25445c8cdf021f2b003b74fd638e69bb1959dde8e370e8cc1e4fa" - }, - "./node_modules/@types/node/path.d.ts": { - "version": "84044697c8b3e08ef24e4b32cfe6440143d07e469a5e34bda0635276d32d9f35", - "signature": "84044697c8b3e08ef24e4b32cfe6440143d07e469a5e34bda0635276d32d9f35" - }, - "./node_modules/@types/node/perf_hooks.d.ts": { - "version": "0b6098fedb648cab8091cca2b022a5c729b6ef18da923852033f495907cb1a45", - "signature": "0b6098fedb648cab8091cca2b022a5c729b6ef18da923852033f495907cb1a45" - }, - "./node_modules/@types/node/process.d.ts": { - "version": "0e0d58f5e90c0a270dac052b9c5ad8ccdfc8271118c2105b361063218d528d6e", - "signature": "0e0d58f5e90c0a270dac052b9c5ad8ccdfc8271118c2105b361063218d528d6e" - }, - "./node_modules/@types/node/punycode.d.ts": { - "version": "30ec6f9c683b988c3cfaa0c4690692049c4e7ed7dc6f6e94f56194c06b86f5e1", - "signature": "30ec6f9c683b988c3cfaa0c4690692049c4e7ed7dc6f6e94f56194c06b86f5e1" - }, - "./node_modules/@types/node/querystring.d.ts": { - "version": "9f633ecf3e065ff82c19eccab35c8aa1d6d5d1a49af282dc29ef5a64cca34164", - "signature": "9f633ecf3e065ff82c19eccab35c8aa1d6d5d1a49af282dc29ef5a64cca34164" - }, - "./node_modules/@types/node/readline.d.ts": { - "version": "6b2bb67b0942bcfce93e1d6fad5f70afd54940a2b13df7f311201fba54b2cbe9", - "signature": "6b2bb67b0942bcfce93e1d6fad5f70afd54940a2b13df7f311201fba54b2cbe9" - }, - "./node_modules/@types/node/repl.d.ts": { - "version": "dd3706b25d06fe23c73d16079e8c66ac775831ef419da00716bf2aee530a04a4", - "signature": "dd3706b25d06fe23c73d16079e8c66ac775831ef419da00716bf2aee530a04a4" - }, - "./node_modules/@types/node/stream.d.ts": { - "version": "d74b8e644da7415e3757a17a42b7f284597b577e3c87b80f4b3ba0cc2db1184f", - "signature": "d74b8e644da7415e3757a17a42b7f284597b577e3c87b80f4b3ba0cc2db1184f" - }, - "./node_modules/@types/node/string_decoder.d.ts": { - "version": "7e62aac2cc9c0710d772047ad89e8d7117f52592c791eb995ce1f865fedab432", - "signature": "7e62aac2cc9c0710d772047ad89e8d7117f52592c791eb995ce1f865fedab432" - }, - "./node_modules/@types/node/timers.d.ts": { - "version": "b40652bf8ce4a18133b31349086523b219724dca8df3448c1a0742528e7ad5b9", - "signature": "b40652bf8ce4a18133b31349086523b219724dca8df3448c1a0742528e7ad5b9" - }, - "./node_modules/@types/node/tls.d.ts": { - "version": "424bc64b2794d9280c1e1f4a3518ba9d285385a16d84753a6427bb469e582eca", - "signature": "424bc64b2794d9280c1e1f4a3518ba9d285385a16d84753a6427bb469e582eca" - }, - "./node_modules/@types/node/trace_events.d.ts": { - "version": "a77fdb357c78b70142b2fdbbfb72958d69e8f765fd2a3c69946c1018e89d4638", - "signature": "a77fdb357c78b70142b2fdbbfb72958d69e8f765fd2a3c69946c1018e89d4638" - }, - "./node_modules/@types/node/tty.d.ts": { - "version": "3c2ac350c3baa61fd2b1925844109e098f4376d0768a4643abc82754fd752748", - "signature": "3c2ac350c3baa61fd2b1925844109e098f4376d0768a4643abc82754fd752748" - }, - "./node_modules/@types/node/url.d.ts": { - "version": "826d48e49c905cedb906cbde6ccaf758827ff5867d4daa006b5a79e0fb489357", - "signature": "826d48e49c905cedb906cbde6ccaf758827ff5867d4daa006b5a79e0fb489357" - }, - "./node_modules/@types/node/util.d.ts": { - "version": "893d1b5dd98f1c01a0ec4122dfd7f774e0fa1560e1aa19e509c96ed543c6244e", - "signature": "893d1b5dd98f1c01a0ec4122dfd7f774e0fa1560e1aa19e509c96ed543c6244e" - }, - "./node_modules/@types/node/v8.d.ts": { - "version": "289be113bad7ee27ee7fa5b1e373c964c9789a5e9ed7db5ddcb631371120b953", - "signature": "289be113bad7ee27ee7fa5b1e373c964c9789a5e9ed7db5ddcb631371120b953" - }, - "./node_modules/@types/node/vm.d.ts": { - "version": "e4abb8eaa8a7d78236be0f8342404aab076668d20590209e32fdeb924588531e", - "signature": "e4abb8eaa8a7d78236be0f8342404aab076668d20590209e32fdeb924588531e" - }, - "./node_modules/@types/node/worker_threads.d.ts": { - "version": "1b4db6ed54916341a48bb81cfd9f910999b3bcd6b71c6a4c7416532a6908775d", - "signature": "1b4db6ed54916341a48bb81cfd9f910999b3bcd6b71c6a4c7416532a6908775d" - }, - "./node_modules/@types/node/zlib.d.ts": { - "version": "f409183966a1dd93d3a9cd1d54fbeb85c73101e87cd5b19467c5e37b252f3fd8", - "signature": "f409183966a1dd93d3a9cd1d54fbeb85c73101e87cd5b19467c5e37b252f3fd8" - }, - "./node_modules/@types/node/base.d.ts": { - "version": "5ff4ecfd544d596de3c8011a6d44c59443c85e1f99065095e556b15237eb39ac", - "signature": "5ff4ecfd544d596de3c8011a6d44c59443c85e1f99065095e556b15237eb39ac" - }, - "./node_modules/@types/node/ts3.2/fs.d.ts": { - "version": "12b2608d6074167c331c9c3c6994a57819f6ff934c7fd4527e23aabf56d4c8d1", - "signature": "12b2608d6074167c331c9c3c6994a57819f6ff934c7fd4527e23aabf56d4c8d1" - }, - "./node_modules/@types/node/ts3.2/util.d.ts": { - "version": "ffc1cd688606ad1ddb59a40e8f3defbde907af2a3402d1d9ddf69accb2903f07", - "signature": "ffc1cd688606ad1ddb59a40e8f3defbde907af2a3402d1d9ddf69accb2903f07" - }, - "./node_modules/@types/node/ts3.2/globals.d.ts": { - "version": "4926e99d2ad39c0bbd36f2d37cc8f52756bc7a5661ad7b12815df871a4b07ba1", - "signature": "4926e99d2ad39c0bbd36f2d37cc8f52756bc7a5661ad7b12815df871a4b07ba1" - }, - "./node_modules/@types/node/ts3.2/base.d.ts": { - "version": "8a70903bbbdad1d58e3936ca90b3ad993e54827ea324e20f2f63cef4e14e9d55", - "signature": "8a70903bbbdad1d58e3936ca90b3ad993e54827ea324e20f2f63cef4e14e9d55" - }, - "./node_modules/@types/node/assert.d.ts": { - "version": "f61a4062a627acbe5c4a9650319132ec8fa7fe2f276a7f40a056e59c2a877e04", - "signature": "f61a4062a627acbe5c4a9650319132ec8fa7fe2f276a7f40a056e59c2a877e04" - }, - "./node_modules/@types/node/ts3.2/index.d.ts": { - "version": "9522f3e35b412f2f17974b1431a1b18d06e0a8f614a0700c37220a4afb04afa8", - "signature": "9522f3e35b412f2f17974b1431a1b18d06e0a8f614a0700c37220a4afb04afa8" - }, - "./node_modules/@types/range-parser/index.d.ts": { - "version": "4e88b833be14c7f384e0dcd57bb30acd799e8e34d212635d693e41a75a71164b", - "signature": "4e88b833be14c7f384e0dcd57bb30acd799e8e34d212635d693e41a75a71164b" - }, - "./node_modules/@types/express-serve-static-core/index.d.ts": { - "version": "a3c58104e1f519cb211279ab6a0dc70e6232f7c7eb11b6a0ca0b43d7e3e72983", - "signature": "a3c58104e1f519cb211279ab6a0dc70e6232f7c7eb11b6a0ca0b43d7e3e72983" - }, - "./node_modules/@types/mime/index.d.ts": { - "version": "be27a64e821a3e5af838650e4aa25805c60f057d0c37a9762c378d19d364b3e6", - "signature": "be27a64e821a3e5af838650e4aa25805c60f057d0c37a9762c378d19d364b3e6" - }, - "./node_modules/@types/serve-static/index.d.ts": { - "version": "cdbae5083ef8f786069519405ca1f1e2ce72b9efebdf5e1931584fba747f3bc0", - "signature": "cdbae5083ef8f786069519405ca1f1e2ce72b9efebdf5e1931584fba747f3bc0" - }, - "./node_modules/@types/connect/index.d.ts": { - "version": "e6ffa74698f0a1d23e4223242ed7dcdb89d02bbbb063a1930e9f91d0385abe16", - "signature": "e6ffa74698f0a1d23e4223242ed7dcdb89d02bbbb063a1930e9f91d0385abe16" - }, - "./node_modules/@types/body-parser/index.d.ts": { - "version": "ebddbd167c2fabd0151f50e5df94ca6d845149c47521280d8867afe3429dd078", - "signature": "ebddbd167c2fabd0151f50e5df94ca6d845149c47521280d8867afe3429dd078" - }, - "./node_modules/@types/qs/index.d.ts": { - "version": "7bc3168fdda8512614c9b6627fbd356043e61070639879cf23d102265259730c", - "signature": "7bc3168fdda8512614c9b6627fbd356043e61070639879cf23d102265259730c" - }, - "./node_modules/@types/express/index.d.ts": { - "version": "ead1ed9dd4874f4907a506a31e4fe9c4e079b42816f6b7ea5016a6d5ddf2fde3", - "signature": "ead1ed9dd4874f4907a506a31e4fe9c4e079b42816f6b7ea5016a6d5ddf2fde3" - }, - "./src/Utils.ts": { - "version": "3fafe931d1756c86680c24af41a389419674bffacc5a2113e7bad6228aeca27a", - "signature": "2336cc1135d6c2625d134e4f9efd92bd7a8d032a46a6b07704955fc942ee2e60" - }, - "./src/HttpError.ts": { - "version": "4c20f2f3d3b94dce23f5a7e1f69f513418e54d5ad29dda562d8d5b83a8a4b26a", - "signature": "a3ad2414c8f96cc5a0133dd38723f942bea58067e7e284646f73d20e81351f21" - }, - "../node_modules/@types/nunjucks/index.d.ts": { - "version": "47081001316dd776632f5bf4954183ba40a0690d1dff832cc709685950e25471", - "signature": "47081001316dd776632f5bf4954183ba40a0690d1dff832cc709685950e25471" - }, - "../node_modules/@types/config/index.d.ts": { - "version": "a2841f04e5d6e69661720db979db826a07dd2c2c6b170fb5fb8ff2680692e922", - "signature": "a2841f04e5d6e69661720db979db826a07dd2c2c6b170fb5fb8ff2680692e922" - }, - "../node_modules/@types/uuid/interfaces.d.ts": { - "version": "5cc5d6f26a50072d51c4ea3a85ee65574b7fa2ae48261ae27b07014695638c50", - "signature": "5cc5d6f26a50072d51c4ea3a85ee65574b7fa2ae48261ae27b07014695638c50" - }, - "../node_modules/@types/uuid/index.d.ts": { - "version": "f961dd194a4ed86a12a6e651bd1fc10d1cea2084b4dbb1a2bb8f3af9ee03a964", - "signature": "f961dd194a4ed86a12a6e651bd1fc10d1cea2084b4dbb1a2bb8f3af9ee03a964" - }, - "../node_modules/@types/mysql/index.d.ts": { - "version": "c31e81b6cf25fee45088689e5043c6243284a7ac1ec9368094d901ea5602bd7b", - "signature": "c31e81b6cf25fee45088689e5043c6243284a7ac1ec9368094d901ea5602bd7b" - }, - "./src/db/Migration.ts": { - "version": "8561d53e8860d46b21bdbdac51e3d68a13a574cb37b6920989df2b6b78f8f371", - "signature": "15cb26bcb2cc6c96ef080c577563c71543e177f199ea5a247beff26ed754d9ed" - }, - "./src/db/MysqlConnectionManager.ts": { - "version": "055fbe99285d902e53ea0eb853696dcb2e35adeb942ce8da515a0be2df99b756", - "signature": "3e6e686f61efa3d2d3312b282bfb08ae6396618d8ff7ee8dee15cb25c5858bf7" - }, - "./src/db/Query.ts": { - "version": "a43192457b79127d344087091c80d4189964edf4ddc86ed476b12d176e22fc70", - "signature": "d37930d32d2842039847f68b7b40855622404378811df23f4d3eac7d15cbb896" - }, - "./src/db/Validator.ts": { - "version": "826ebd3a2060d1a07c14dcb14c41c11ff3ec7d252dc48a3f92744e21e0a76bf4", - "signature": "b279f5059a857fb54b3044e90179aa5f73429ce96be90970a4d94c1aea03aba9" - }, - "./src/Pagination.ts": { - "version": "23419feda468a0484fb8780cf80767efac9944791043c035e5a99772fe0080f1", - "signature": "6aea91ae324d18504957ff52a8c31bb61d15b9895e7bff53e5044f77e0146d1f" - }, - "./src/db/Model.ts": { - "version": "b48b098abf85a4bc11f5c2ccfe735edc3f9e9d808ba3de340961fbfb0a4e6e5f", - "signature": "44fbb4d4ec99995dd6da1283a1ced2f9e56dbb699ba0ab92792c583940f0d04f" - }, - "./src/models/Log.ts": { - "version": "306ff5f522fd37e6e19b207f9d82d147a56f4050ec66e2cb912d84cb6253fb77", - "signature": "fe0f4f3bef6db55a4dba56e4b229cb5abd2225af12fe217d38268e42f2308ae9" - }, - "./src/Logger.ts": { - "version": "37e9fda17789d37a59318f932373d0f7a91fb440c04ad127735535a42b447d03", - "signature": "543d96fd1f49c36dd6061439805a2b7bb91e50b2fa9e552d9ee7906b5d0cf01a" - }, - "../node_modules/@types/ws/index.d.ts": { - "version": "75ce9fa40c86cf9a4f0a546958cc0e5104bf53e408e0f2b71c3757a610adb6b4", - "signature": "75ce9fa40c86cf9a4f0a546958cc0e5104bf53e408e0f2b71c3757a610adb6b4" - }, - "./src/WebSocketListener.ts": { - "version": "ee4d3c2651d6c8e064dba83ba650d92e3a0bd07f9914638d68f43377635e848a", - "signature": "3d406b9aa15cc62f4365fb0ef64aa0f4118003d1166e20927bf299d6f30a07e8" - }, - "./src/ApplicationComponent.ts": { - "version": "23f6f0f5509fc12ddb5e0eec429d448be24fb254d7aef3b6e9a61cf90e797d63", - "signature": "c09ebb6934e80943c2f3699fd8bf29d012281049af1c7f5af576e57fefc0f8d7" - }, - "./src/Controller.ts": { - "version": "2a243e8b262491c3c6ed7f50a87d64d063b964d5e52cc210d36876a579f8b75d", - "signature": "9aee25f9c3c8b8f7d12d49f9e357afe668608a43a2edbecce146829ef028a60a" - }, - "./src/Application.ts": { - "version": "4ece554b602b37717c7ffa073555d58445036b3d8022557ce87c63c294d9a10d", - "signature": "29edd84f74afdcf8d07c6e76f4aa5c69dc883310b5f7612a2f10bc1dbf0dbf63" - }, - "../node_modules/@types/nodemailer/lib/dkim/index.d.ts": { - "version": "971b6006a4610efd734e051f5d1421f87bc0c73bfc3cd205819236d497cba1e4", - "signature": "971b6006a4610efd734e051f5d1421f87bc0c73bfc3cd205819236d497cba1e4" - }, - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts": { - "version": "d9be0e7047e30df44cafac456f18dd3f43af529225ad747c7330e835da6b370c", - "signature": "d9be0e7047e30df44cafac456f18dd3f43af529225ad747c7330e835da6b370c" - }, - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts": { - "version": "a9d32ef46fa1075bfeff4a4ab96c1331254558865ca9c7bf383712baa297f065", - "signature": "a9d32ef46fa1075bfeff4a4ab96c1331254558865ca9c7bf383712baa297f065" - }, - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts": { - "version": "bf54271e59aa6df4670631b40b7fc0666e8ac0978fae18f96ed99f37fb8b3936", - "signature": "bf54271e59aa6df4670631b40b7fc0666e8ac0978fae18f96ed99f37fb8b3936" - }, - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts": { - "version": "689b62c8e45e8f63dacf3a6de1655e06d524cf853f9a96f9446461553c49bd84", - "signature": "689b62c8e45e8f63dacf3a6de1655e06d524cf853f9a96f9446461553c49bd84" - }, - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts": { - "version": "559d3b5e23b28a26355233cd54b496701c6837fd9b539511158e44c028d7b8c5", - "signature": "559d3b5e23b28a26355233cd54b496701c6837fd9b539511158e44c028d7b8c5" - }, - "../node_modules/@types/nodemailer/lib/shared.d.ts": { - "version": "06fdb97fb4733b9ff5a24fc3bf9c0713c93231d361f27ea95ed05bfab679ac61", - "signature": "06fdb97fb4733b9ff5a24fc3bf9c0713c93231d361f27ea95ed05bfab679ac61" - }, - "../node_modules/@types/nodemailer/lib/json-transport.d.ts": { - "version": "f5af2c4bee48b94b4a247464406d600b5232036df7b835d16504f84303977474", - "signature": "f5af2c4bee48b94b4a247464406d600b5232036df7b835d16504f84303977474" - }, - "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts": { - "version": "2739f287a5d26386849a9e1fd05421ece3366ae533f7569654ab73cc74d30aae", - "signature": "2739f287a5d26386849a9e1fd05421ece3366ae533f7569654ab73cc74d30aae" - }, - "../node_modules/@types/nodemailer/lib/ses-transport.d.ts": { - "version": "dd335f22e01cf7abb3445c837e2a8a94650fc23b37572876581d36c2b8f96cb8", - "signature": "dd335f22e01cf7abb3445c837e2a8a94650fc23b37572876581d36c2b8f96cb8" - }, - "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts": { - "version": "f44c29cd43b1b2ebcb49b51b3315c85d00fd5ed66b80a7c7a629ad27132bf213", - "signature": "f44c29cd43b1b2ebcb49b51b3315c85d00fd5ed66b80a7c7a629ad27132bf213" - }, - "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts": { - "version": "b5a4a00d0d26d9ca9ce666ea46c2cf84f12139aa4e57b648d22c33362e25554a", - "signature": "b5a4a00d0d26d9ca9ce666ea46c2cf84f12139aa4e57b648d22c33362e25554a" - }, - "../node_modules/@types/nodemailer/lib/stream-transport.d.ts": { - "version": "d10c3e41c9d07022049b732e9b5e8d16a5e584393cfa589b299ac29630ab671a", - "signature": "d10c3e41c9d07022049b732e9b5e8d16a5e584393cfa589b299ac29630ab671a" - }, - "../node_modules/@types/nodemailer/index.d.ts": { - "version": "7c9ad24b7763a35bc2b94f495ee80a4f08f5d7f6fa677526c9931af90fdf6da5", - "signature": "7c9ad24b7763a35bc2b94f495ee80a4f08f5d7f6fa677526c9931af90fdf6da5" - }, - "../node_modules/@types/mjml/index.d.ts": { - "version": "29e6dd4f18688f445ad9d23a358c37e55493894768940449c28ddad2bc118aab", - "signature": "29e6dd4f18688f445ad9d23a358c37e55493894768940449c28ddad2bc118aab" - }, - "./src/Mail.ts": { - "version": "a321991e2afb9ffb308a93936b46edcdc3102e3a18cb55ef23b1d0dc0549cca1", - "signature": "ad7c8edfa4c0e9e5d8325228af68fc92d018fa2cf702dcb5cd793956cabf1036" - }, - "./src/index.ts": { - "version": "21dac02d30e8c4266c081894aa6d0938b620d7ba06c0d3632ab790ccd517be5f", - "signature": "22e5bc2b989e4d6c621ac438700ed6567b63dcc6ff67bffb54e0ede2ef45e721" - }, - "./src/components/CsrfProtectionComponent.ts": { - "version": "d2ac8a26b66bd7c9de6e85eb0fa31223f786636f129be51098e1121f12e91e32", - "signature": "7a208416ae5bfff4bd1f0fe507fdbb23b2026149b1e70c6dd5d52efbf834f049" - }, - "./src/components/ExpressAppComponent.ts": { - "version": "0bf2a47d0497ea6ba5231e5020ea560eafd6272045080f0407b39b42417eb486", - "signature": "1893d96ff6b9d0cc83f76612c4bf48e999e361ffecb6b68b79d908eec4657f80" - }, - "./src/components/FormHelperComponent.ts": { - "version": "6cf21d88314fafeb0499a1b926c9b9ca8f475d7c92c15ca3a06ce40cccb1e1b3", - "signature": "8993db64158ef1437c674fad5f62785b854f777a02273eaa1e3eafd54e670288" - }, - "../node_modules/@types/on-finished/index.d.ts": { - "version": "c69767317aec528b574762b18727db85eef7cf66f33617cc0ee905cbe5a43d97", - "signature": "c69767317aec528b574762b18727db85eef7cf66f33617cc0ee905cbe5a43d97" - }, - "./src/components/LogRequestsComponent.ts": { - "version": "770580c0d8eb417d27b035cba14d18ecc137a72f2a7b2efc4b4e8c7fb94898e6", - "signature": "bdcfd88a151dbdba6a995f66555318bfa466c0b520ebaecbfa4174a7b6107c57" - }, - "./src/components/MailComponent.ts": { - "version": "91f2f87f4c14bdbce5a4a0636f0982482bb7e09390f68fbbc7d7a9ab77cc3388", - "signature": "4051b829aa2900c112bf181f96346150ddb248cb3c0a9395cb592d1f4e46a177" - }, - "./src/components/MaintenanceComponent.ts": { - "version": "0cb6d08367b949a54920be736a0ca7e7d0bd48219082a9743afc7f669f5f4c9a", - "signature": "94f0546ca6c9f8255740ecc19c3883310bec540012c28e9652c10ffb477ac8dc" - }, - "./src/components/MysqlComponent.ts": { - "version": "842acfffb204031d1f449a32f36448f2289e7b979d7438c6922932cfdc3bce66", - "signature": "140c141b201786ff49458f1cbcce2b77052881d168f7ae79d0582185b9aeedee" - }, - "./src/components/RedirectBackComponent.ts": { - "version": "aeed6a141a3295545db9a40642601a3002a75c47ce4fc7803d8103cf03f1707f", - "signature": "ed921b450bfc547bd1ea2edbc0e77d71505c432d8ca141c62a5e4883849eb54c" - }, - "../node_modules/@types/redis/ts3.1/index.d.ts": { - "version": "c09db611897b893f45fc71ba3c8f0ad2b578911f5454b0063cd099d7d7c82ad5", - "signature": "c09db611897b893f45fc71ba3c8f0ad2b578911f5454b0063cd099d7d7c82ad5" - }, - "../node_modules/@types/express/index.d.ts": { - "version": "ead1ed9dd4874f4907a506a31e4fe9c4e079b42816f6b7ea5016a6d5ddf2fde3", - "signature": "ead1ed9dd4874f4907a506a31e4fe9c4e079b42816f6b7ea5016a6d5ddf2fde3" - }, - "../node_modules/@types/express-session/index.d.ts": { - "version": "3e03ea3c4d568a10e41f540bc891c5fb42c036a430187132e599176f7974eaf7", - "signature": "3e03ea3c4d568a10e41f540bc891c5fb42c036a430187132e599176f7974eaf7" - }, - "../node_modules/@types/ioredis/index.d.ts": { - "version": "1b5e15b9e676645123c3f17404ac4736e4dd5eba8189a572b23a09a569989d8f", - "signature": "1b5e15b9e676645123c3f17404ac4736e4dd5eba8189a572b23a09a569989d8f" - }, - "../node_modules/@types/connect-redis/index.d.ts": { - "version": "36b01abb39b1ea4a1081cc4347e4ea09878e015e2ff66bdd1ad25e17f318c93a", - "signature": "36b01abb39b1ea4a1081cc4347e4ea09878e015e2ff66bdd1ad25e17f318c93a" - }, - "./src/components/RedisComponent.ts": { - "version": "c6b95081fc7b4ece4a2b3883e478bfffddb1815fc11b2bf75297056f9c47454c", - "signature": "ed4412eae1fff66afd3f714dd1004aa6d7cb69229fe67e1ce192820c373ec191" - }, - "./src/components/ServeStaticDirectoryComponent.ts": { - "version": "3afaf06a8cadbcc74427bf9e7b987b9cc9413c503df01b8f3f58c7c975cd2dd6", - "signature": "b01e48eed7e04d1f10b2d3f9df5c87b08fd86bc77c5dd1dca7a8ced23f369841" - }, - "../node_modules/@types/connect-flash/index.d.ts": { - "version": "eb6dd47dbc0800f57073a9d5388e0e8cffdc34cc5f3910d8311cdf4a799d5eaa", - "signature": "eb6dd47dbc0800f57073a9d5388e0e8cffdc34cc5f3910d8311cdf4a799d5eaa" - }, - "./src/components/SessionComponent.ts": { - "version": "0ca82dd47213589b8cb879aa25f456157de6d1984ca7e7b157bfd63598c570bb", - "signature": "0b026cff1f2e9cd1e4f22be20024b1cf6c22478229a25adb77dc7086a3438dd4" - }, - "../node_modules/@types/cookie/index.d.ts": { - "version": "90643a7d80d87f379ec4c6448a4b5e473b7fb64062ac649a61d93b3a1a8b2180", - "signature": "90643a7d80d87f379ec4c6448a4b5e473b7fb64062ac649a61d93b3a1a8b2180" - }, - "../node_modules/@types/cookie-parser/index.d.ts": { - "version": "8d77ed4e39114c32edc2e35b683b6f54a6b3292ecdf392e4bfc5f726734955d8", - "signature": "8d77ed4e39114c32edc2e35b683b6f54a6b3292ecdf392e4bfc5f726734955d8" - }, - "./src/components/WebSocketServerComponent.ts": { - "version": "b3705ed6eee728898b2a34b5bbf731c86dceefb9ae2a38a8a40efc8f4b57b759", - "signature": "752b5d1937d8bc6a5e9146dda0bf0de9d9a2470735a86a7471a0de8e06dc3f38" - }, - "./src/migrations/CreateLogsTable.ts": { - "version": "943eae01421342827dfb1e345f225da23605264c72a71fa1b1bff23a80746672", - "signature": "f773ac0c4f5a4182882e6aba40dae5613738f0931b3affe712fdeb7d2b9953c7" - }, - "./src/migrations/CreateMigrationsTable.ts": { - "version": "53c71413d70f75862c2c2b56ecddbf01e592cf7106b5182969f762790e2bbf20", - "signature": "604690ec96d6d95d9d9a3b3662caf186f87c49d8e88a3a36bf63a29449fd0a9c" - }, - "./src/types/Express.d.ts": { - "version": "ace3d52e1a42f5ba8324fba29ca2327a1e0789b8c1a2a51e04fa537254fdc6b9", - "signature": "ace3d52e1a42f5ba8324fba29ca2327a1e0789b8c1a2a51e04fa537254fdc6b9" - } - }, - "options": { - "module": 1, - "esModuleInterop": true, - "outDir": "./dist", - "target": 2, - "strict": true, - "lib": [ - "lib.es2020.d.ts" - ], - "typeRoots": [ - "./node_modules/@types", - "./src/types" - ], - "composite": true, - "rootDir": "./src", - "declaration": true, - "declarationMap": true, - "configFilePath": "./tsconfig.json" - }, - "referencedMap": { - "./node_modules/typescript/lib/lib.es5.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2016.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.core.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.collection.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.generator.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.iterable.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.promise.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.proxy.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.reflect.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.symbol.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2016.array.include.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.object.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.string.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.intl.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.intl.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.promise.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.regexp.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.array.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.object.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.string.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.symbol.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.bigint.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.promise.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.string.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.esnext.intl.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/globals.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/async_hooks.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/buffer.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/events/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/child_process.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/cluster.d.ts": [ - "./node_modules/@types/node/child_process.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/console.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/constants.d.ts": [ - "./node_modules/@types/node/os.d.ts", - "./node_modules/@types/node/crypto.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/crypto.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/dgram.d.ts": [ - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/dns.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/dns.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/domain.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/events.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/fs.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/http.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/http2.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/tls.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/https.d.ts": [ - "./node_modules/@types/node/tls.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/inspector.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/module.d.ts": [ - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/net.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/dns.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/os.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/path.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/perf_hooks.d.ts": [ - "./node_modules/@types/node/async_hooks.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/process.d.ts": [ - "./node_modules/@types/node/tty.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/punycode.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/querystring.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/readline.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/repl.d.ts": [ - "./node_modules/@types/node/readline.d.ts", - "./node_modules/@types/node/vm.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/stream.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/string_decoder.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/timers.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/tls.d.ts": [ - "./node_modules/@types/node/crypto.d.ts", - "./node_modules/@types/node/dns.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/trace_events.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/tty.d.ts": [ - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/url.d.ts": [ - "./node_modules/@types/node/querystring.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/util.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/v8.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/vm.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/worker_threads.d.ts": [ - "./node_modules/@types/node/vm.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/zlib.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/base.d.ts": [ - "./node_modules/@types/node/globals.d.ts", - "./node_modules/@types/node/async_hooks.d.ts", - "./node_modules/@types/node/buffer.d.ts", - "./node_modules/@types/node/child_process.d.ts", - "./node_modules/@types/node/cluster.d.ts", - "./node_modules/@types/node/console.d.ts", - "./node_modules/@types/node/constants.d.ts", - "./node_modules/@types/node/crypto.d.ts", - "./node_modules/@types/node/dgram.d.ts", - "./node_modules/@types/node/dns.d.ts", - "./node_modules/@types/node/domain.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/http2.d.ts", - "./node_modules/@types/node/https.d.ts", - "./node_modules/@types/node/inspector.d.ts", - "./node_modules/@types/node/module.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/os.d.ts", - "./node_modules/@types/node/path.d.ts", - "./node_modules/@types/node/perf_hooks.d.ts", - "./node_modules/@types/node/process.d.ts", - "./node_modules/@types/node/punycode.d.ts", - "./node_modules/@types/node/querystring.d.ts", - "./node_modules/@types/node/readline.d.ts", - "./node_modules/@types/node/repl.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/string_decoder.d.ts", - "./node_modules/@types/node/timers.d.ts", - "./node_modules/@types/node/tls.d.ts", - "./node_modules/@types/node/trace_events.d.ts", - "./node_modules/@types/node/tty.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/v8.d.ts", - "./node_modules/@types/node/vm.d.ts", - "./node_modules/@types/node/worker_threads.d.ts", - "./node_modules/@types/node/zlib.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/ts3.2/fs.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/ts3.2/util.d.ts": [ - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts" - ], - "./node_modules/@types/node/ts3.2/globals.d.ts": [ - "./node_modules/@types/node/globals.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/ts3.2/base.d.ts": [ - "./node_modules/@types/node/base.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts", - "./node_modules/@types/node/ts3.2/globals.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/util.d.ts" - ], - "./node_modules/@types/node/assert.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/ts3.2/index.d.ts": [ - "./node_modules/@types/node/ts3.2/base.d.ts", - "./node_modules/@types/node/assert.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/range-parser/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/express-serve-static-core/index.d.ts": [ - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/range-parser/index.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/mime/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/serve-static/index.d.ts": [ - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/mime/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/connect/index.d.ts": [ - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/body-parser/index.d.ts": [ - "./node_modules/@types/connect/index.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/qs/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/express/index.d.ts": [ - "./node_modules/@types/body-parser/index.d.ts", - "./node_modules/@types/serve-static/index.d.ts", - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/qs/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/Utils.ts": [ - "./node_modules/@types/node/crypto.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/HttpError.ts": [ - "./src/Utils.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nunjucks/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/config/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/uuid/interfaces.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/uuid/index.d.ts": [ - "../node_modules/@types/uuid/interfaces.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/mysql/index.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/tls.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/db/Migration.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/db/MysqlConnectionManager.ts": [ - "../node_modules/@types/mysql/index.d.ts", - "../node_modules/@types/config/index.d.ts", - "./src/db/Migration.ts", - "./src/Logger.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/db/Query.ts": [ - "./src/db/MysqlConnectionManager.ts", - "../node_modules/@types/mysql/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/db/Validator.ts": [ - "./src/db/Model.ts", - "./src/db/Query.ts", - "../node_modules/@types/mysql/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/Pagination.ts": [ - "./src/db/Model.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/db/Model.ts": [ - "./src/db/MysqlConnectionManager.ts", - "./src/db/Validator.ts", - "../node_modules/@types/mysql/index.d.ts", - "./src/db/Query.ts", - "./node_modules/@types/express/index.d.ts", - "./src/Pagination.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/models/Log.ts": [ - "./src/db/Model.ts", - "./src/Logger.ts", - "./src/db/Validator.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/Logger.ts": [ - "../node_modules/@types/config/index.d.ts", - "../node_modules/@types/uuid/index.d.ts", - "./src/models/Log.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/ws/index.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/https.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/zlib.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/WebSocketListener.ts": [ - "../node_modules/@types/ws/index.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/ApplicationComponent.ts": [ - "./node_modules/@types/express/index.d.ts", - "./src/Logger.ts", - "./src/Utils.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/Controller.ts": [ - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/express-serve-static-core/index.d.ts", - "../node_modules/@types/config/index.d.ts", - "./src/Logger.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/Application.ts": [ - "./node_modules/@types/express/index.d.ts", - "./src/HttpError.ts", - "../node_modules/@types/nunjucks/index.d.ts", - "./src/Logger.ts", - "./src/WebSocketListener.ts", - "./src/ApplicationComponent.ts", - "./src/Controller.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/dkim/index.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts": [ - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/url.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/dkim/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/tls.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/shared.d.ts": [ - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/json-transport.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts": [ - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/ses-transport.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/stream-transport.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/index.d.ts": [ - "../node_modules/@types/nodemailer/lib/json-transport.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts", - "../node_modules/@types/nodemailer/lib/ses-transport.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts", - "../node_modules/@types/nodemailer/lib/stream-transport.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/mjml/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/Mail.ts": [ - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/config/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nunjucks/index.d.ts", - "./node_modules/@types/node/util.d.ts", - "./src/Utils.ts", - "../node_modules/@types/mjml/index.d.ts", - "./node_modules/@types/node/querystring.d.ts", - "./src/Logger.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/index.ts": [ - "./src/ApplicationComponent.ts", - "./src/Mail.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/CsrfProtectionComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/node/crypto.d.ts", - "./src/HttpError.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/ExpressAppComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "./src/Logger.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/FormHelperComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/on-finished/index.d.ts": [ - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/LogRequestsComponent.ts": [ - "./src/ApplicationComponent.ts", - "../node_modules/@types/on-finished/index.d.ts", - "./src/Logger.ts", - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/MailComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "./src/Mail.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/MaintenanceComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "./src/HttpError.ts", - "./src/Application.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/MysqlComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "./src/db/MysqlConnectionManager.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/RedirectBackComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "../node_modules/@types/on-finished/index.d.ts", - "./src/Logger.ts", - "./src/HttpError.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/redis/ts3.1/index.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/express/index.d.ts": [ - "./node_modules/@types/body-parser/index.d.ts", - "./node_modules/@types/serve-static/index.d.ts", - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/qs/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/express-session/index.d.ts": [ - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/ioredis/index.d.ts": [ - "./node_modules/@types/node/tls.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/connect-redis/index.d.ts": [ - "./node_modules/@types/express/index.d.ts", - "../node_modules/@types/express-session/index.d.ts", - "../node_modules/@types/ioredis/index.d.ts", - "../node_modules/@types/redis/ts3.1/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/RedisComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "../node_modules/@types/redis/ts3.1/index.d.ts", - "../node_modules/@types/config/index.d.ts", - "./src/Logger.ts", - "../node_modules/@types/express-session/index.d.ts", - "../node_modules/@types/connect-redis/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/ServeStaticDirectoryComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/connect-flash/index.d.ts": [ - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/SessionComponent.ts": [ - "./src/ApplicationComponent.ts", - "../node_modules/@types/express-session/index.d.ts", - "../node_modules/@types/config/index.d.ts", - "./src/components/RedisComponent.ts", - "../node_modules/@types/connect-flash/index.d.ts", - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/cookie/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/cookie-parser/index.d.ts": [ - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/WebSocketServerComponent.ts": [ - "./src/ApplicationComponent.ts", - "./node_modules/@types/express/index.d.ts", - "../node_modules/@types/ws/index.d.ts", - "./src/Logger.ts", - "../node_modules/@types/cookie/index.d.ts", - "../node_modules/@types/cookie-parser/index.d.ts", - "../node_modules/@types/config/index.d.ts", - "./src/components/ExpressAppComponent.ts", - "./src/Application.ts", - "./src/components/RedisComponent.ts", - "./src/WebSocketListener.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/migrations/CreateLogsTable.ts": [ - "./src/db/Migration.ts", - "./src/db/MysqlConnectionManager.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/migrations/CreateMigrationsTable.ts": [ - "./src/db/Migration.ts", - "./src/db/MysqlConnectionManager.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/types/Express.d.ts": [ - "../node_modules/@types/nunjucks/index.d.ts", - "./src/db/Model.ts", - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ] - }, - "exportedModulesMap": { - "./node_modules/typescript/lib/lib.es5.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2016.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.core.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.collection.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.generator.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.iterable.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.promise.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.proxy.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.reflect.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.symbol.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2016.array.include.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.object.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.string.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.intl.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.intl.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.promise.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2018.regexp.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.array.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.object.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.string.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2019.symbol.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.bigint.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.promise.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.string.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/typescript/lib/lib.esnext.intl.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/globals.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/async_hooks.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/buffer.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/events/index.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/child_process.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/cluster.d.ts": [ - "./node_modules/@types/node/child_process.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/console.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/constants.d.ts": [ - "./node_modules/@types/node/os.d.ts", - "./node_modules/@types/node/crypto.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/crypto.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/dgram.d.ts": [ - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/dns.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/dns.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/domain.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/events.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/fs.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/http.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/http2.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/tls.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/https.d.ts": [ - "./node_modules/@types/node/tls.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/inspector.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/module.d.ts": [ - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/net.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/dns.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/os.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/path.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/perf_hooks.d.ts": [ - "./node_modules/@types/node/async_hooks.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/process.d.ts": [ - "./node_modules/@types/node/tty.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/punycode.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/querystring.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/readline.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/repl.d.ts": [ - "./node_modules/@types/node/readline.d.ts", - "./node_modules/@types/node/vm.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/stream.d.ts": [ - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/string_decoder.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/timers.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/tls.d.ts": [ - "./node_modules/@types/node/crypto.d.ts", - "./node_modules/@types/node/dns.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/trace_events.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/tty.d.ts": [ - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/url.d.ts": [ - "./node_modules/@types/node/querystring.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/util.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/v8.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/vm.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/worker_threads.d.ts": [ - "./node_modules/@types/node/vm.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/zlib.d.ts": [ - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/base.d.ts": [ - "./node_modules/@types/node/globals.d.ts", - "./node_modules/@types/node/async_hooks.d.ts", - "./node_modules/@types/node/buffer.d.ts", - "./node_modules/@types/node/child_process.d.ts", - "./node_modules/@types/node/cluster.d.ts", - "./node_modules/@types/node/console.d.ts", - "./node_modules/@types/node/constants.d.ts", - "./node_modules/@types/node/crypto.d.ts", - "./node_modules/@types/node/dgram.d.ts", - "./node_modules/@types/node/dns.d.ts", - "./node_modules/@types/node/domain.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/http2.d.ts", - "./node_modules/@types/node/https.d.ts", - "./node_modules/@types/node/inspector.d.ts", - "./node_modules/@types/node/module.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/os.d.ts", - "./node_modules/@types/node/path.d.ts", - "./node_modules/@types/node/perf_hooks.d.ts", - "./node_modules/@types/node/process.d.ts", - "./node_modules/@types/node/punycode.d.ts", - "./node_modules/@types/node/querystring.d.ts", - "./node_modules/@types/node/readline.d.ts", - "./node_modules/@types/node/repl.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/string_decoder.d.ts", - "./node_modules/@types/node/timers.d.ts", - "./node_modules/@types/node/tls.d.ts", - "./node_modules/@types/node/trace_events.d.ts", - "./node_modules/@types/node/tty.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/v8.d.ts", - "./node_modules/@types/node/vm.d.ts", - "./node_modules/@types/node/worker_threads.d.ts", - "./node_modules/@types/node/zlib.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/ts3.2/fs.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/ts3.2/util.d.ts": [ - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts" - ], - "./node_modules/@types/node/ts3.2/globals.d.ts": [ - "./node_modules/@types/node/globals.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/ts3.2/base.d.ts": [ - "./node_modules/@types/node/base.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts", - "./node_modules/@types/node/ts3.2/globals.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/util.d.ts" - ], - "./node_modules/@types/node/assert.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/node/ts3.2/index.d.ts": [ - "./node_modules/@types/node/ts3.2/base.d.ts", - "./node_modules/@types/node/assert.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/range-parser/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/express-serve-static-core/index.d.ts": [ - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/range-parser/index.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/mime/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/serve-static/index.d.ts": [ - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/mime/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/connect/index.d.ts": [ - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/body-parser/index.d.ts": [ - "./node_modules/@types/connect/index.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/qs/index.d.ts": [ - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./node_modules/@types/express/index.d.ts": [ - "./node_modules/@types/body-parser/index.d.ts", - "./node_modules/@types/serve-static/index.d.ts", - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/qs/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/HttpError.ts": [ - "./src/Utils.ts" - ], - "../node_modules/@types/nunjucks/index.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/config/index.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/uuid/interfaces.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/uuid/index.d.ts": [ - "../node_modules/@types/uuid/interfaces.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/mysql/index.d.ts": [ - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/node/tls.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/db/MysqlConnectionManager.ts": [ - "../node_modules/@types/mysql/index.d.ts", - "./src/db/Migration.ts" - ], - "./src/db/Query.ts": [ - "../node_modules/@types/mysql/index.d.ts", - "./src/db/MysqlConnectionManager.ts" - ], - "./src/db/Validator.ts": [ - "../node_modules/@types/mysql/index.d.ts", - "./src/db/Model.ts", - "./src/db/Query.ts" - ], - "./src/Pagination.ts": [ - "./src/db/Model.ts" - ], - "./src/db/Model.ts": [ - "./node_modules/@types/express/index.d.ts", - "./src/db/Query.ts", - "./src/db/Validator.ts", - "../node_modules/@types/mysql/index.d.ts" - ], - "./src/models/Log.ts": [ - "./src/Logger.ts", - "./src/db/Model.ts" - ], - "../node_modules/@types/ws/index.d.ts": [ - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/node/http.d.ts", - "../node_modules/@types/node/https.d.ts", - "../node_modules/@types/node/net.d.ts", - "../node_modules/@types/node/url.d.ts", - "../node_modules/@types/node/zlib.d.ts", - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/WebSocketListener.ts": [ - "../node_modules/@types/ws/index.d.ts", - "./node_modules/@types/node/http.d.ts" - ], - "./src/ApplicationComponent.ts": [ - "./node_modules/@types/express/index.d.ts" - ], - "./src/Controller.ts": [ - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/express-serve-static-core/index.d.ts" - ], - "./src/Application.ts": [ - "./src/Controller.ts", - "./src/WebSocketListener.ts", - "./src/ApplicationComponent.ts" - ], - "../node_modules/@types/nodemailer/lib/dkim/index.d.ts": [ - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts": [ - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts": [ - "../node_modules/@types/node/http.d.ts", - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts": [ - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/node/net.d.ts", - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/node/url.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/dkim/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts": [ - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts": [ - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/node/net.d.ts", - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/node/tls.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/shared.d.ts": [ - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/json-transport.d.ts": [ - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts": [ - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/ses-transport.d.ts": [ - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts": [ - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts": [ - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/lib/stream-transport.d.ts": [ - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/nodemailer/index.d.ts": [ - "../node_modules/@types/nodemailer/lib/json-transport.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts", - "../node_modules/@types/nodemailer/lib/ses-transport.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts", - "../node_modules/@types/nodemailer/lib/stream-transport.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/mjml/index.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/Mail.ts": [ - "../node_modules/@types/nodemailer/index.d.ts" - ], - "./src/components/CsrfProtectionComponent.ts": [ - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "./src/components/ExpressAppComponent.ts": [ - "./node_modules/@types/express/index.d.ts", - "./node_modules/@types/node/http.d.ts", - "./src/ApplicationComponent.ts" - ], - "./src/components/FormHelperComponent.ts": [ - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "../node_modules/@types/on-finished/index.d.ts": [ - "../node_modules/@types/node/http.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/LogRequestsComponent.ts": [ - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "./src/components/MailComponent.ts": [ - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "./src/components/MaintenanceComponent.ts": [ - "./src/Application.ts", - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "./src/components/MysqlComponent.ts": [ - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "./src/components/RedirectBackComponent.ts": [ - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "../node_modules/@types/redis/ts3.1/index.d.ts": [ - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/express/index.d.ts": [ - "../node_modules/@types/body-parser/index.d.ts", - "../node_modules/@types/serve-static/index.d.ts", - "../node_modules/@types/express-serve-static-core/index.d.ts", - "../node_modules/@types/qs/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/express-session/index.d.ts": [ - "../node_modules/@types/express/index.d.ts", - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/ioredis/index.d.ts": [ - "../node_modules/@types/node/tls.d.ts", - "../node_modules/@types/node/stream.d.ts", - "../node_modules/@types/node/events.d.ts", - "../node_modules/@types/node/ts3.2/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/connect-redis/index.d.ts": [ - "../node_modules/@types/express/index.d.ts", - "../node_modules/@types/express-session/index.d.ts", - "../node_modules/@types/ioredis/index.d.ts", - "../node_modules/@types/redis/ts3.1/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/RedisComponent.ts": [ - "./node_modules/@types/express/index.d.ts", - "../node_modules/@types/express-session/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "./src/components/ServeStaticDirectoryComponent.ts": [ - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "../node_modules/@types/connect-flash/index.d.ts": [ - "../node_modules/@types/express/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/SessionComponent.ts": [ - "./src/components/RedisComponent.ts", - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "../node_modules/@types/cookie/index.d.ts": [ - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "../node_modules/@types/cookie-parser/index.d.ts": [ - "../node_modules/@types/express/index.d.ts", - "../node_modules/@types/node/fs.d.ts", - "../node_modules/@types/node/ts3.2/fs.d.ts", - "../node_modules/@types/node/util.d.ts", - "../node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/components/WebSocketServerComponent.ts": [ - "./src/Application.ts", - "./src/components/ExpressAppComponent.ts", - "./src/components/RedisComponent.ts", - "./node_modules/@types/express/index.d.ts", - "./src/ApplicationComponent.ts" - ], - "./src/migrations/CreateLogsTable.ts": [ - "./src/db/Migration.ts" - ], - "./src/migrations/CreateMigrationsTable.ts": [ - "./src/db/Migration.ts" - ], - "./src/types/Express.d.ts": [ - "../node_modules/@types/nunjucks/index.d.ts", - "./src/db/Model.ts", - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts" - ], - "./src/index.ts": [ - "./src/ApplicationComponent.ts", - "./src/Mail.ts" - ] - }, - "semanticDiagnosticsPerFile": [ - "./node_modules/typescript/lib/lib.es5.d.ts", - "./node_modules/typescript/lib/lib.es2015.d.ts", - "./node_modules/typescript/lib/lib.es2016.d.ts", - "./node_modules/typescript/lib/lib.es2017.d.ts", - "./node_modules/typescript/lib/lib.es2018.d.ts", - "./node_modules/typescript/lib/lib.es2019.d.ts", - "./node_modules/typescript/lib/lib.es2020.d.ts", - "./node_modules/typescript/lib/lib.es2015.core.d.ts", - "./node_modules/typescript/lib/lib.es2015.collection.d.ts", - "./node_modules/typescript/lib/lib.es2015.generator.d.ts", - "./node_modules/typescript/lib/lib.es2015.iterable.d.ts", - "./node_modules/typescript/lib/lib.es2015.promise.d.ts", - "./node_modules/typescript/lib/lib.es2015.proxy.d.ts", - "./node_modules/typescript/lib/lib.es2015.reflect.d.ts", - "./node_modules/typescript/lib/lib.es2015.symbol.d.ts", - "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts", - "./node_modules/typescript/lib/lib.es2016.array.include.d.ts", - "./node_modules/typescript/lib/lib.es2017.object.d.ts", - "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts", - "./node_modules/typescript/lib/lib.es2017.string.d.ts", - "./node_modules/typescript/lib/lib.es2017.intl.d.ts", - "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts", - "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts", - "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts", - "./node_modules/typescript/lib/lib.es2018.intl.d.ts", - "./node_modules/typescript/lib/lib.es2018.promise.d.ts", - "./node_modules/typescript/lib/lib.es2018.regexp.d.ts", - "./node_modules/typescript/lib/lib.es2019.array.d.ts", - "./node_modules/typescript/lib/lib.es2019.object.d.ts", - "./node_modules/typescript/lib/lib.es2019.string.d.ts", - "./node_modules/typescript/lib/lib.es2019.symbol.d.ts", - "./node_modules/typescript/lib/lib.es2020.bigint.d.ts", - "./node_modules/typescript/lib/lib.es2020.promise.d.ts", - "./node_modules/typescript/lib/lib.es2020.string.d.ts", - "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts", - "./node_modules/typescript/lib/lib.esnext.intl.d.ts", - "./node_modules/@types/node/globals.d.ts", - "./node_modules/@types/node/async_hooks.d.ts", - "./node_modules/@types/node/buffer.d.ts", - "../node_modules/@types/events/index.d.ts", - "./node_modules/@types/node/child_process.d.ts", - "./node_modules/@types/node/cluster.d.ts", - "./node_modules/@types/node/console.d.ts", - "./node_modules/@types/node/constants.d.ts", - "./node_modules/@types/node/crypto.d.ts", - "./node_modules/@types/node/dgram.d.ts", - "./node_modules/@types/node/dns.d.ts", - "./node_modules/@types/node/domain.d.ts", - "./node_modules/@types/node/events.d.ts", - "./node_modules/@types/node/fs.d.ts", - "./node_modules/@types/node/http.d.ts", - "./node_modules/@types/node/http2.d.ts", - "./node_modules/@types/node/https.d.ts", - "./node_modules/@types/node/inspector.d.ts", - "./node_modules/@types/node/module.d.ts", - "./node_modules/@types/node/net.d.ts", - "./node_modules/@types/node/os.d.ts", - "./node_modules/@types/node/path.d.ts", - "./node_modules/@types/node/perf_hooks.d.ts", - "./node_modules/@types/node/process.d.ts", - "./node_modules/@types/node/punycode.d.ts", - "./node_modules/@types/node/querystring.d.ts", - "./node_modules/@types/node/readline.d.ts", - "./node_modules/@types/node/repl.d.ts", - "./node_modules/@types/node/stream.d.ts", - "./node_modules/@types/node/string_decoder.d.ts", - "./node_modules/@types/node/timers.d.ts", - "./node_modules/@types/node/tls.d.ts", - "./node_modules/@types/node/trace_events.d.ts", - "./node_modules/@types/node/tty.d.ts", - "./node_modules/@types/node/url.d.ts", - "./node_modules/@types/node/util.d.ts", - "./node_modules/@types/node/v8.d.ts", - "./node_modules/@types/node/vm.d.ts", - "./node_modules/@types/node/worker_threads.d.ts", - "./node_modules/@types/node/zlib.d.ts", - "./node_modules/@types/node/base.d.ts", - "./node_modules/@types/node/ts3.2/fs.d.ts", - "./node_modules/@types/node/ts3.2/util.d.ts", - "./node_modules/@types/node/ts3.2/globals.d.ts", - "./node_modules/@types/node/ts3.2/base.d.ts", - "./node_modules/@types/node/assert.d.ts", - "./node_modules/@types/node/ts3.2/index.d.ts", - "./node_modules/@types/range-parser/index.d.ts", - "./node_modules/@types/express-serve-static-core/index.d.ts", - "./node_modules/@types/mime/index.d.ts", - "./node_modules/@types/serve-static/index.d.ts", - "./node_modules/@types/connect/index.d.ts", - "./node_modules/@types/body-parser/index.d.ts", - "./node_modules/@types/qs/index.d.ts", - "./node_modules/@types/express/index.d.ts", - "./src/Utils.ts", - "./src/HttpError.ts", - "../node_modules/@types/nunjucks/index.d.ts", - "../node_modules/@types/config/index.d.ts", - "../node_modules/@types/uuid/interfaces.d.ts", - "../node_modules/@types/uuid/index.d.ts", - "../node_modules/@types/mysql/index.d.ts", - "./src/db/Migration.ts", - "./src/db/MysqlConnectionManager.ts", - "./src/db/Query.ts", - "./src/db/Validator.ts", - "./src/Pagination.ts", - "./src/db/Model.ts", - "./src/models/Log.ts", - "./src/Logger.ts", - "../node_modules/@types/ws/index.d.ts", - "./src/WebSocketListener.ts", - "./src/ApplicationComponent.ts", - "./src/Controller.ts", - "./src/Application.ts", - "../node_modules/@types/nodemailer/lib/dkim/index.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/mail-message.d.ts", - "../node_modules/@types/nodemailer/lib/xoauth2.d.ts", - "../node_modules/@types/nodemailer/lib/mailer/index.d.ts", - "../node_modules/@types/nodemailer/lib/mime-node/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-connection/index.d.ts", - "../node_modules/@types/nodemailer/lib/shared.d.ts", - "../node_modules/@types/nodemailer/lib/json-transport.d.ts", - "../node_modules/@types/nodemailer/lib/sendmail-transport/index.d.ts", - "../node_modules/@types/nodemailer/lib/ses-transport.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-pool/index.d.ts", - "../node_modules/@types/nodemailer/lib/smtp-transport.d.ts", - "../node_modules/@types/nodemailer/lib/stream-transport.d.ts", - "../node_modules/@types/nodemailer/index.d.ts", - "../node_modules/@types/mjml/index.d.ts", - "./src/Mail.ts", - "./src/components/CsrfProtectionComponent.ts", - "./src/components/ExpressAppComponent.ts", - "./src/components/FormHelperComponent.ts", - "../node_modules/@types/on-finished/index.d.ts", - "./src/components/LogRequestsComponent.ts", - "./src/components/MailComponent.ts", - "./src/components/MaintenanceComponent.ts", - "./src/components/MysqlComponent.ts", - "./src/components/RedirectBackComponent.ts", - "../node_modules/@types/redis/ts3.1/index.d.ts", - "../node_modules/@types/express/index.d.ts", - "../node_modules/@types/express-session/index.d.ts", - "../node_modules/@types/ioredis/index.d.ts", - "../node_modules/@types/connect-redis/index.d.ts", - "./src/components/RedisComponent.ts", - "./src/components/ServeStaticDirectoryComponent.ts", - "../node_modules/@types/connect-flash/index.d.ts", - "./src/components/SessionComponent.ts", - "../node_modules/@types/cookie/index.d.ts", - "../node_modules/@types/cookie-parser/index.d.ts", - "./src/components/WebSocketServerComponent.ts", - "./src/migrations/CreateLogsTable.ts", - "./src/migrations/CreateMigrationsTable.ts", - "./src/types/Express.d.ts", - "./src/index.ts" - ] - }, - "version": "3.8.3" -} \ No newline at end of file diff --git a/views/auth/account.njk b/views/auth/account.njk new file mode 100644 index 0000000..88c7bf0 --- /dev/null +++ b/views/auth/account.njk @@ -0,0 +1,104 @@ +{% extends 'layouts/base.njk' %} +{% import 'macros.njk' as macros %} + +{% set title = 'Account' %} +{% set decription = 'Manage your account settings and data.' %} + +{% block body %} +
+
+

Personal information

+ + {% if display_email_warning and emails | length <= 0 %} + {{ macros.message('warning', 'To avoid losing access to your account, please add an email address.') }} + {% endif %} + + {% for field in user.getPersonalInfoFields() %} +

{{ field.name }}: {{ field.value }}

+ {% endfor %} + +

Contact email: {{ main_email.email }} More...

+
+ +
+

{% if has_password %}Change{% else %}Set{% endif %} password

+ +
+ {% if has_password %} + {{ macros.field(_locals, 'password', 'current_password', null, 'Current password') }} + {% endif %} + {{ macros.field(_locals, 'password', 'new_password', null, 'New password') }} + {{ macros.field(_locals, 'password', 'new_password_confirmation', null, 'New password confirmation') }} + + + + {{ macros.csrf(getCsrfToken) }} +
+
+ +
+

Email addresses

+ + + + + + + + + + + + {% for email in emails %} + {% if email.id == user.main_email_id %} + + + + + + {% endif %} + {% endfor %} + {% for email in emails %} + {% if email.id != user.main_email_id %} + + + + + + {% endif %} + {% endfor %} + +
TypeAddressActions
Main{{ email.email }}
Secondary{{ email.email }} +
+ + + + {{ macros.csrf(getCsrfToken) }} +
+ +
+ + + + {{ macros.csrf(getCsrfToken) }} +
+
+ +
+

Add an email address:

+ + {{ macros.field(_locals, 'email', 'email', null, 'Choose a safe email address', 'An email address we can use to identify you in case you lose access to your account', 'required') }} + + + + {{ macros.csrf(getCsrfToken) }} +
+
+
+{% endblock %} diff --git a/views/auth/auth.njk b/views/auth/auth.njk new file mode 100644 index 0000000..545135e --- /dev/null +++ b/views/auth/auth.njk @@ -0,0 +1,79 @@ +{% extends 'layouts/base.njk' %} +{% import 'macros.njk' as macros %} + +{% set title = 'Authentication / Registration' %} +{% set decription = 'Join ' + app.name + ' and share your files!' %} +{% set h1 = 'Authentication and registration' %} + +{% block body %} +
+ {% set queryStr = '' %} + {% set previousUrl = getPreviousUrl() %} + {% if query.redirect_uri | length %} + {% set queryStr = '?' + querystring.stringify({redirect_uri: query.redirect_uri}) %} + {% elif previousUrl | length %} + {% set queryStr = '?' + querystring.stringify({redirect_uri: previousUrl}) %} + {% endif %} + +
+

Log in

+ +
+ {{ macros.field(_locals, 'text', 'identifier', query.identifier or '', 'Your email address or username', null, 'required') }} + + {{ macros.field(_locals, 'password', 'password', null, 'Your password', 'Do not fill to log in via magic link.') }} + + {{ macros.field(_locals, 'checkbox', 'persist_session', null, 'Stay logged in on this computer.') }} + + + + {{ macros.csrf(getCsrfToken) }} +
+
+ +
+

Register with email

+ +
+ + {{ macros.csrf(getCsrfToken) }} + + {% if has_username %} + {{ macros.field(_locals, 'text', 'name', null, 'Choose your username', 'This cannot be changed later.', 'pattern="[0-9a-z_-]+" required') }} + {% endif %} + + {{ macros.field(_locals, 'email', 'identifier', null, 'Your email address', null, 'required') }} + + {{ macros.field(_locals, 'checkbox', 'terms', null, 'I accept the Terms Of Services.' | safe, null, 'required') }} + + +
+
+ + {% if register_with_password %} +
+

Register with password

+ +
+ + {{ macros.csrf(getCsrfToken) }} + +
+

Username

+ {{ macros.field(_locals, 'text', 'identifier', null, 'Choose your username', 'This cannot be changed later.', 'pattern="[0-9a-z_-]+" required') }} +
+ +
+

Password

+ {{ macros.field(_locals, 'password', 'password', null, 'Choose a password', null, 'required') }} + {{ macros.field(_locals, 'password', 'password_confirmation', null, 'Confirm your password', null, 'required') }} +
+ + {{ macros.field(_locals, 'checkbox', 'terms', null, 'I accept the Terms Of Services.' | safe, null, 'required') }} + + +
+
+ {% endif %} +
+{% endblock %} diff --git a/views/backend/accounts_approval.njk b/views/backend/accounts_approval.njk new file mode 100644 index 0000000..cc0ae9f --- /dev/null +++ b/views/backend/accounts_approval.njk @@ -0,0 +1,59 @@ +{% extends 'layouts/base.njk' %} + +{% set title = app.name + ' - Review accounts' %} + +{% block body %} +

Accounts pending review

+ +
+ + + + + + + + + + + + {% for user in accounts %} + + + + + + + + {% endfor %} + +
#NameMain emailRegistered atAction
{{ user.id }}{{ user.name }}{{ user.mainEmail.getOrFail().email | default('No email') }}{{ user.created_at.toISOString() }} +
+
+ + + {{ macros.csrf(getCsrfToken) }} +
+ +
+ + + {{ macros.csrf(getCsrfToken) }} +
+
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/views/backend/index.njk b/views/backend/index.njk new file mode 100644 index 0000000..cd556bf --- /dev/null +++ b/views/backend/index.njk @@ -0,0 +1,28 @@ +{% extends 'layouts/base.njk' %} + +{% set title = app.name + ' backend' %} + +{% block body %} +
+ {{ macros.breadcrumb('Backend') }} + +

App administration

+ + +
+{% endblock %} \ No newline at end of file diff --git a/views/errors/400.njk b/views/errors/400.njk new file mode 100644 index 0000000..aa8e1f7 --- /dev/null +++ b/views/errors/400.njk @@ -0,0 +1,2 @@ +{% extends 'errors/error.njk' %} +{% import 'macros.njk' as macros %} diff --git a/views/errors/401.njk b/views/errors/401.njk new file mode 100644 index 0000000..aa8e1f7 --- /dev/null +++ b/views/errors/401.njk @@ -0,0 +1,2 @@ +{% extends 'errors/error.njk' %} +{% import 'macros.njk' as macros %} diff --git a/views/errors/403.njk b/views/errors/403.njk new file mode 100644 index 0000000..aa8e1f7 --- /dev/null +++ b/views/errors/403.njk @@ -0,0 +1,2 @@ +{% extends 'errors/error.njk' %} +{% import 'macros.njk' as macros %} diff --git a/views/errors/404.njk b/views/errors/404.njk new file mode 100644 index 0000000..aa8e1f7 --- /dev/null +++ b/views/errors/404.njk @@ -0,0 +1,2 @@ +{% extends 'errors/error.njk' %} +{% import 'macros.njk' as macros %} diff --git a/views/errors/429.njk b/views/errors/429.njk new file mode 100644 index 0000000..aa8e1f7 --- /dev/null +++ b/views/errors/429.njk @@ -0,0 +1,2 @@ +{% extends 'errors/error.njk' %} +{% import 'macros.njk' as macros %} diff --git a/views/errors/500.njk b/views/errors/500.njk new file mode 100644 index 0000000..aa8e1f7 --- /dev/null +++ b/views/errors/500.njk @@ -0,0 +1,2 @@ +{% extends 'errors/error.njk' %} +{% import 'macros.njk' as macros %} diff --git a/views/errors/503.njk b/views/errors/503.njk new file mode 100644 index 0000000..aa8e1f7 --- /dev/null +++ b/views/errors/503.njk @@ -0,0 +1,2 @@ +{% extends 'errors/error.njk' %} +{% import 'macros.njk' as macros %} diff --git a/views/errors/error.njk b/views/errors/error.njk new file mode 100644 index 0000000..86a1c77 --- /dev/null +++ b/views/errors/error.njk @@ -0,0 +1,37 @@ +{% extends 'layouts/barebone.njk' %} + +{% set title = error_code + ' - ' + error_message %} + +{% block _stylesheets %} + +{% endblock %} + +{% block _body %} + + +
+ {% if flash %} + {{ macros.messages(flash) }} + {% endif %} + +
{{ error_code }}
+
{{ error_message }}
+
{{ error_instructions|safe }}
+ + +
+ +
+ Error ID: {{ error_id | default('Request has no indentifier.') }} +
+ If you think this isn't right, please contact us with the above error ID at + {{ app.contact_email }}. +
+{% endblock %} \ No newline at end of file diff --git a/views/layouts/barebone.njk b/views/layouts/barebone.njk new file mode 100644 index 0000000..3a82d94 --- /dev/null +++ b/views/layouts/barebone.njk @@ -0,0 +1,37 @@ + + + + + {{ title }} + + + + + + + + {% if description %} + + {% endif %} + + {% if refresh_after %} + + {% endif %} + + {% block _stylesheets %}{% endblock %} + {% block _scripts %} + + {% endblock %} + + + +
+ {% block header %}{% endblock %} +
+ +{% block _body %}{% endblock %} + +
{% block footer %}{% endblock %}
+ + + \ No newline at end of file diff --git a/views/macros.njk b/views/macros.njk new file mode 100644 index 0000000..b62170b --- /dev/null +++ b/views/macros.njk @@ -0,0 +1,168 @@ +{% macro message(type, content, raw=false, discreet=false) %} +
+ + + {{ content|safe if raw else content }} + +
+{% endmacro %} + +{% macro messages(flash) %} + {% set flashed = flash() %} + {% set display = 0 %} + + {% for type, bag in flashed %} + {% if bag|length %} + {% set display = 1 %} + {% endif %} + {% endfor %} + + {% if display %} +
+ {% for type, bag in flashed %} + {% for content in bag %} + {{ message(type, content) }} + {% endfor %} + {% endfor %} +
+ {% endif %} +{% endmacro %} + +{% macro csrf(getCsrfToken) %} + +{% endmacro %} + +{% macro field(_locals, type, name, value, placeholder, hint, validation_attributes='', extraData='', icon=null) %} + {% set validation = _locals.validation() %} + {% set validation = validation[name] if validation[name] or null %} + {% set previousFormData = _locals.previousFormData() %} + {% set value = previousFormData[name] or value or validation.value or '' %} + + {% if type == 'hidden' %} + {% if validation %} + {{ message('error', validation.message) }} + {% endif %} + + {% else %} +
+
+ {% if icon != null %} + {% if icon.startsWith('fa') %} + + {% else %} + + {% endif %} + {% endif %} + + {% if type == 'duration' %} +
+ {% for f in extraData %} +
+ {% if previousFormData[name] %} + {% set v = value[f] %} + {% else %} + {% set v = (value % 60) if f == 's' else (((value - value % 60) / 60 % 60) if f == 'm' else ((value - value % 3600) / 3600 if f == 'h')) %} + {% endif %} + + +
+ {% endfor %} +
+ {% elseif type == 'select' %} + + + {% elseif type == 'textarea' %} + + {% else %} + + {% endif %} + + +
+ + {{ fieldError(_locals, name) }} + {% if hint %} +
{{ hint }}
+ {% endif %} +
+ {% endif %} +{% endmacro %} + +{% macro fieldError(_locals, name) %} + {% set validation = _locals.validation() %} + {% set validation = validation[name] if validation[name] or null %} + {% if validation %} +
{{ validation.message }}
+ {% endif %} +{% endmacro %} + +{% macro websocket(websocketUrl, listener, reconnectOnClose = 1, checkFunction = 0) %} + +{% endmacro %} + +{% macro paginate(pagination, routeName) %} + {% if pagination.hasPrevious() or pagination.hasNext() %} + + {% endif %} +{% endmacro %} + +{% macro breadcrumb(currentPageTitle, pages=[]) %} + +{% endmacro %} diff --git a/views/magic_link.njk b/views/magic_link.njk new file mode 100644 index 0000000..a575e76 --- /dev/null +++ b/views/magic_link.njk @@ -0,0 +1,18 @@ +{% extends 'layouts/base.njk' %} + +{% set actionType = magicLink.action_type %} +{% set h1 = 'Magic Link' + (' - ' + actionType if actionType) %} +{% set title = app.name + ' ' + h1 %} + +{% block body %} +
+
+ {% if err %} + {{ macros.message('error', err) }} + {% else %} + {{ macros.message('success', 'Success!') }} +

You can now close this page.

+ {% endif %} +
+
+{% endblock %} diff --git a/views/magic_link_lobby.njk b/views/magic_link_lobby.njk new file mode 100644 index 0000000..b86ceb4 --- /dev/null +++ b/views/magic_link_lobby.njk @@ -0,0 +1,57 @@ +{% extends 'layouts/base.njk' %} + +{% set h1 = 'Authentication lobby' %} +{% set title = app.name + ' ' + h1 %} + +{% block body %} +
+
+ {{ macros.message('success', 'We sent a link to ' + email + '. To authenticate, open it from any device.') }} + {{ macros.message('info', 'This link will be valid for and can only be used once.', true, true) }} + +

Waiting for you to open the link...

+
+
+{% endblock %} + +{% block scripts %} + + + {{ macros.websocket(websocketUrl, 'websocketListen', 1, 'isValid') }} +{% endblock %} diff --git a/views/mails/account_review_notice.mjml.njk b/views/mails/account_review_notice.mjml.njk new file mode 100644 index 0000000..43b1ae3 --- /dev/null +++ b/views/mails/account_review_notice.mjml.njk @@ -0,0 +1,41 @@ +{% extends 'mails/base_layout.mjml.njk' %} + +{% block body %} + + + + {% if approved %} + Your registration was approved! + {% else %} + Sorry, your registration was rejected. + {% endif %} + + + {% if approved %} + An administrator approved your registration. You can now log in to your account. + {% else %} + Your registration was rejected and your account was deleted from our database. + If you believe that this is an error, please contact us via email. + {% endif %} + + + {% if approved %} + Login + {% endif %} + + +{% endblock %} + +{% block text %} + {% if approved %} + Hi + Your registration was approved! + + You can now log in to your account by follwing this link: {{ link|safe }} + {% else %} + Hi + Sorry, your registration was rejected. Your account was deleted from our database. + + If you believe that this is an error, please contact us via email. + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/views/mails/add_email.mjml.njk b/views/mails/add_email.mjml.njk new file mode 100644 index 0000000..fc5e8f0 --- /dev/null +++ b/views/mails/add_email.mjml.njk @@ -0,0 +1,27 @@ +{% extends 'mails/base_layout.mjml.njk' %} + +{% block body %} + + + + Add this email address on {{ app.name }} + + + Someone wants to add {{ mail_to }} to their account. +

+ Do not click on this if this is not you! +
+ + + Add {{ mail_to }} on {{ app.name }} + +
+
+{% endblock %} + +{% block text %} + Hi! + Someone wants to add {{ mail_to }} to their account. + + To add this email address, please follow this link: {{ link|safe }} +{% endblock %} \ No newline at end of file diff --git a/views/mails/base_layout.mjml.njk b/views/mails/base_layout.mjml.njk new file mode 100644 index 0000000..fdae4b5 --- /dev/null +++ b/views/mails/base_layout.mjml.njk @@ -0,0 +1,115 @@ +{% if not text %} + + + {{ mail_subject }} + + + + + + + + + + + + + + + + + + + + + .link { + color: #00766c !important; + text-decoration: none; + } + + + .link:hover { + color: #00a99b !important; + } + + {% block head %}{% endblock %} + + + {% if mail_link %} + + + + Does this mail display improperly? + Open it in the browser + + + + {% endif %} + + + + + {{ app.name }} + + + + + {% block body %}{% endblock %} + + + + + All rights reserved. Contact us at + {{ app.contact_email }} + + + + + +{% else %} + {% block text %}{% endblock %} +{% endif %} \ No newline at end of file diff --git a/views/mails/magic_link.mjml.njk b/views/mails/magic_link.mjml.njk new file mode 100644 index 0000000..208fa4e --- /dev/null +++ b/views/mails/magic_link.mjml.njk @@ -0,0 +1,66 @@ +{% extends 'mails/base_layout.mjml.njk' %} + +{% block body %} + + + + {% if type == 'register' %} + Register an account on {{ app.name }} + {% else %} + Log in to {{ app.name }} + {% endif %} + + + {% if type == 'register' %} + Someone has requested an account registration for {{ mail_to }}. If it was not you, + please ignore this message. + {% else %} + Someone is attempting to log in to your account {{ mail_to }}. + {% endif %} + + + {% if type == 'register' %} + Finalize my account registration + {% else %} + If it is not you, DO NOT CLICK ON THIS BUTTON. + {% endif %} + + + + {% if type == 'login' %} + + + + IP: {{ ip }} + + + Location: {{ geo }} + + + + + Authorize log in + + + + {% endif %} +{% endblock %} + +{% block text %} + {% if type == 'register' %} + Hi! + Someone requested an account registration for {{ mail_to }}. If it was not you, + please ignore this message. + + To finalize your account registration, please follow this link: {{ link|safe }} + {% else %} + Hi! + Someone is attempting to log in to your account {{ mail_to }}. + + If it is not you, DO NOT FOLLOW THIS LINK. + + IP: {{ ip }} + Location: {{ geo }} + To authorize this log in, please follow this link: {{ link|safe }} + {% endif %} +{% endblock %} \ No newline at end of file diff --git a/views/mails/pending_account_review.mjml.njk b/views/mails/pending_account_review.mjml.njk new file mode 100644 index 0000000..0687756 --- /dev/null +++ b/views/mails/pending_account_review.mjml.njk @@ -0,0 +1,26 @@ +{% extends 'mails/base_layout.mjml.njk' %} + +{% block body %} + + + + New user account on {{ app.name }} + + + A new user is pending review on {{ app.name }}. +
+ Username: {{ username }} +
+ + Go to account reviews +
+
+{% endblock %} + +{% block text %} + Hi! + A new user is pending review on {{ app.name }}. + + Username: {{ username }} + To review this account, please follow this link: {{ link|safe }} +{% endblock %} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index d27f30a..f24cc41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,452 +2,548 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fcode-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== dependencies: - "@babel/highlight" "^7.8.3" + "@babel/highlight" "^7.10.4" "@babel/core@^7.1.0", "@babel/core@^7.7.5": - version "7.9.0" - resolved "http://127.0.0.1:4873/@babel%2fcore/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" - integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd" + integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.0" - "@babel/parser" "^7.9.0" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.10" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.5" + "@babel/parser" "^7.12.10" + "@babel/template" "^7.12.7" + "@babel/traverse" "^7.12.10" + "@babel/types" "^7.12.10" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" + lodash "^4.17.19" semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.9.0", "@babel/generator@^7.9.5": - version "7.9.5" - resolved "http://127.0.0.1:4873/@babel%2fgenerator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9" - integrity sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ== +"@babel/generator@^7.12.10", "@babel/generator@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af" + integrity sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA== dependencies: - "@babel/types" "^7.9.5" + "@babel/types" "^7.12.11" jsesc "^2.5.1" - lodash "^4.17.13" source-map "^0.5.0" -"@babel/helper-function-name@^7.9.5": - version "7.9.5" - resolved "http://127.0.0.1:4873/@babel%2fhelper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" - integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== +"@babel/helper-function-name@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz#1fd7738aee5dcf53c3ecff24f1da9c511ec47b42" + integrity sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA== dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.9.5" + "@babel/helper-get-function-arity" "^7.12.10" + "@babel/template" "^7.12.7" + "@babel/types" "^7.12.11" -"@babel/helper-get-function-arity@^7.8.3": - version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fhelper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== +"@babel/helper-get-function-arity@^7.12.10": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz#b158817a3165b5faa2047825dfa61970ddcc16cf" + integrity sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.12.10" -"@babel/helper-member-expression-to-functions@^7.8.3": - version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fhelper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" - integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== +"@babel/helper-member-expression-to-functions@^7.12.7": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz#aa77bd0396ec8114e5e30787efa78599d874a855" + integrity sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.12.7" -"@babel/helper-module-imports@^7.8.3": - version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fhelper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" - integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== +"@babel/helper-module-imports@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb" + integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.12.5" -"@babel/helper-module-transforms@^7.9.0": - version "7.9.0" - resolved "http://127.0.0.1:4873/@babel%2fhelper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" - integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== +"@babel/helper-module-transforms@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c" + integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w== dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-simple-access" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.6" - "@babel/types" "^7.9.0" - lodash "^4.17.13" + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-simple-access" "^7.12.1" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/helper-validator-identifier" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + lodash "^4.17.19" -"@babel/helper-optimise-call-expression@^7.8.3": - version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fhelper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" - integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== +"@babel/helper-optimise-call-expression@^7.12.10": + version "7.12.10" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz#94ca4e306ee11a7dd6e9f42823e2ac6b49881e2d" + integrity sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.12.10" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fhelper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" - integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== -"@babel/helper-replace-supers@^7.8.6": - version "7.8.6" - resolved "http://127.0.0.1:4873/@babel%2fhelper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" - integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== +"@babel/helper-replace-supers@^7.12.1": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz#ea511658fc66c7908f923106dd88e08d1997d60d" + integrity sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA== dependencies: - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.6" + "@babel/helper-member-expression-to-functions" "^7.12.7" + "@babel/helper-optimise-call-expression" "^7.12.10" + "@babel/traverse" "^7.12.10" + "@babel/types" "^7.12.11" -"@babel/helper-simple-access@^7.8.3": - version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fhelper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" - integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== +"@babel/helper-simple-access@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136" + integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA== dependencies: - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/types" "^7.12.1" -"@babel/helper-split-export-declaration@^7.8.3": - version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fhelper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== +"@babel/helper-split-export-declaration@^7.11.0", "@babel/helper-split-export-declaration@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz#1b4cc424458643c47d37022223da33d76ea4603a" + integrity sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g== dependencies: - "@babel/types" "^7.8.3" + "@babel/types" "^7.12.11" -"@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": - version "7.9.5" - resolved "http://127.0.0.1:4873/@babel%2fhelper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" - integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== +"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" + integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== -"@babel/helpers@^7.9.0": - version "7.9.2" - resolved "http://127.0.0.1:4873/@babel%2fhelpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" - integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== +"@babel/helpers@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.5.tgz#1a1ba4a768d9b58310eda516c449913fe647116e" + integrity sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA== dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" -"@babel/highlight@^7.8.3": - version "7.9.0" - resolved "http://127.0.0.1:4873/@babel%2fhighlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== dependencies: - "@babel/helper-validator-identifier" "^7.9.0" + "@babel/helper-validator-identifier" "^7.10.4" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.7.5", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": - version "7.9.4" - resolved "http://127.0.0.1:4873/@babel%2fparser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" - integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== +"@babel/parser@^7.1.0", "@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79" + integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "http://127.0.0.1:4873/@babel%2fplugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + 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 "http://127.0.0.1:4873/@babel%2fplugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + 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.8.3" - resolved "http://127.0.0.1:4873/@babel%2fplugin-syntax-class-properties/-/plugin-syntax-class-properties-7.8.3.tgz#6cb933a8872c8d359bfde69bbeaae5162fd1e8f7" - integrity sha512-UcAyQWg2bAN647Q+O811tG9MrJ38Z10jjhQdKNAL8fsyPzE3cCN/uT+f55cFVY4aGO4jqJAvmqsuY3GQDwAoXg== + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz#bcb297c5366e79bebadef509549cd93b04f19978" + integrity sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" + +"@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 "http://127.0.0.1:4873/@babel%2fplugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + 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.8.3" - resolved "http://127.0.0.1:4873/@babel%2fplugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.8.3.tgz#3995d7d7ffff432f6ddc742b47e730c054599897" - integrity sha512-Zpg2Sgc++37kuFl6ppq2Q7Awc6E6AIW671x5PY8E/f7MCIyPPGK/EoeZXvvY3P42exZ3Q4/t3YOzP/HiN79jDg== + 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.8.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fplugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + 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.8.3" - resolved "http://127.0.0.1:4873/@babel%2fplugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" - integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== + 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.8.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "http://127.0.0.1:4873/@babel%2fplugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + 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 "http://127.0.0.1:4873/@babel%2fplugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + 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 "http://127.0.0.1:4873/@babel%2fplugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + 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/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": - version "7.8.6" - resolved "http://127.0.0.1:4873/@babel%2ftemplate/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz#dd6c0b357ac1bb142d98537450a319625d13d2a0" + integrity sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.7.4", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": - version "7.9.5" - resolved "http://127.0.0.1:4873/@babel%2ftraverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2" - integrity sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ== +"@babel/runtime@^7.8.7": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.5" - "@babel/helper-function-name" "^7.9.5" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.9.0" - "@babel/types" "^7.9.5" + regenerator-runtime "^0.13.4" + +"@babel/template@^7.10.4", "@babel/template@^7.12.7", "@babel/template@^7.3.3": + version "7.12.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc" + integrity sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.12.7" + "@babel/types" "^7.12.7" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.10", "@babel/traverse@^7.12.5": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.12.tgz#d0cd87892704edd8da002d674bc811ce64743376" + integrity sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w== + dependencies: + "@babel/code-frame" "^7.12.11" + "@babel/generator" "^7.12.11" + "@babel/helper-function-name" "^7.12.11" + "@babel/helper-split-export-declaration" "^7.12.11" + "@babel/parser" "^7.12.11" + "@babel/types" "^7.12.12" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.13" + lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5": - version "7.9.5" - resolved "http://127.0.0.1:4873/@babel%2ftypes/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444" - integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg== +"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.12", "@babel/types@^7.12.5", "@babel/types@^7.12.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.12.12" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299" + integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ== dependencies: - "@babel/helper-validator-identifier" "^7.9.5" - lodash "^4.17.13" + "@babel/helper-validator-identifier" "^7.12.11" + lodash "^4.17.19" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" - resolved "http://127.0.0.1:4873/@bcoe%2fv8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== "@cnakazawa/watch@^1.0.3": version "1.0.4" - resolved "http://127.0.0.1:4873/@cnakazawa%2fwatch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== dependencies: exec-sh "^0.3.2" minimist "^1.2.0" +"@eslint/eslintrc@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.3.0.tgz#d736d6963d7003b6514e6324bec9c602ac340318" + integrity sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + lodash "^4.17.20" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + "@istanbuljs/load-nyc-config@^1.0.0": - version "1.0.0" - resolved "http://127.0.0.1:4873/@istanbuljs%2fload-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" - integrity sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg== + 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.2" - resolved "http://127.0.0.1:4873/@istanbuljs%2fschema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@jest/console@^25.4.0": - version "25.4.0" - resolved "http://127.0.0.1:4873/@jest%2fconsole/-/console-25.4.0.tgz#e2760b532701137801ba824dcff6bc822c961bac" - integrity sha512-CfE0erx4hdJ6t7RzAcE1wLG6ZzsHSmybvIBQDoCkDM1QaSeWL9wJMzID/2BbHHa7ll9SsbbK43HjbERbBaFX2A== +"@jest/console@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== dependencies: - "@jest/types" "^25.4.0" - chalk "^3.0.0" - jest-message-util "^25.4.0" - jest-util "^25.4.0" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^26.6.2" + jest-util "^26.6.2" slash "^3.0.0" -"@jest/core@^25.4.0": - version "25.4.0" - resolved "http://127.0.0.1:4873/@jest%2fcore/-/core-25.4.0.tgz#cc1fe078df69b8f0fbb023bb0bcee23ef3b89411" - integrity sha512-h1x9WSVV0+TKVtATGjyQIMJENs8aF6eUjnCoi4jyRemYZmekLr8EJOGQqTWEX8W6SbZ6Skesy9pGXrKeAolUJw== +"@jest/core@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== dependencies: - "@jest/console" "^25.4.0" - "@jest/reporters" "^25.4.0" - "@jest/test-result" "^25.4.0" - "@jest/transform" "^25.4.0" - "@jest/types" "^25.4.0" + "@jest/console" "^26.6.2" + "@jest/reporters" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" ansi-escapes "^4.2.1" - chalk "^3.0.0" + chalk "^4.0.0" exit "^0.1.2" - graceful-fs "^4.2.3" - jest-changed-files "^25.4.0" - jest-config "^25.4.0" - jest-haste-map "^25.4.0" - jest-message-util "^25.4.0" - jest-regex-util "^25.2.6" - jest-resolve "^25.4.0" - jest-resolve-dependencies "^25.4.0" - jest-runner "^25.4.0" - jest-runtime "^25.4.0" - jest-snapshot "^25.4.0" - jest-util "^25.4.0" - jest-validate "^25.4.0" - jest-watcher "^25.4.0" + graceful-fs "^4.2.4" + jest-changed-files "^26.6.2" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-resolve-dependencies "^26.6.3" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + jest-watcher "^26.6.2" micromatch "^4.0.2" p-each-series "^2.1.0" - realpath-native "^2.0.0" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^25.4.0": - version "25.4.0" - resolved "http://127.0.0.1:4873/@jest%2fenvironment/-/environment-25.4.0.tgz#45071f525f0d8c5a51ed2b04fd42b55a8f0c7cb3" - integrity sha512-KDctiak4mu7b4J6BIoN/+LUL3pscBzoUCP+EtSPd2tK9fqyDY5OF+CmkBywkFWezS9tyH5ACOQNtpjtueEDH6Q== +"@jest/environment@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== dependencies: - "@jest/fake-timers" "^25.4.0" - "@jest/types" "^25.4.0" - jest-mock "^25.4.0" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" -"@jest/fake-timers@^25.4.0": - version "25.4.0" - resolved "http://127.0.0.1:4873/@jest%2ffake-timers/-/fake-timers-25.4.0.tgz#3a9a4289ba836abd084953dca406389a57e00fbd" - integrity sha512-lI9z+VOmVX4dPPFzyj0vm+UtaB8dCJJ852lcDnY0uCPRvZAaVGnMwBBc1wxtf+h7Vz6KszoOvKAt4QijDnHDkg== +"@jest/fake-timers@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" + integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== dependencies: - "@jest/types" "^25.4.0" - jest-message-util "^25.4.0" - jest-mock "^25.4.0" - jest-util "^25.4.0" - lolex "^5.0.0" + "@jest/types" "^26.6.2" + "@sinonjs/fake-timers" "^6.0.1" + "@types/node" "*" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-util "^26.6.2" -"@jest/reporters@^25.4.0": - version "25.4.0" - resolved "http://127.0.0.1:4873/@jest%2freporters/-/reporters-25.4.0.tgz#836093433b32ce4e866298af2d6fcf6ed351b0b0" - integrity sha512-bhx/buYbZgLZm4JWLcRJ/q9Gvmd3oUh7k2V7gA4ZYBx6J28pIuykIouclRdiAC6eGVX1uRZT+GK4CQJLd/PwPg== +"@jest/globals@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/types" "^26.6.2" + expect "^26.6.2" + +"@jest/reporters@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^25.4.0" - "@jest/test-result" "^25.4.0" - "@jest/transform" "^25.4.0" - "@jest/types" "^25.4.0" - chalk "^3.0.0" + "@jest/console" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + 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 "^4.0.0" + istanbul-lib-instrument "^4.0.3" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.0.2" - jest-haste-map "^25.4.0" - jest-resolve "^25.4.0" - jest-util "^25.4.0" - jest-worker "^25.4.0" + jest-haste-map "^26.6.2" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" slash "^3.0.0" source-map "^0.6.0" - string-length "^3.1.0" + string-length "^4.0.1" terminal-link "^2.0.0" - v8-to-istanbul "^4.1.3" + v8-to-istanbul "^7.0.0" optionalDependencies: - node-notifier "^6.0.0" + node-notifier "^8.0.0" -"@jest/source-map@^25.2.6": - version "25.2.6" - resolved "http://127.0.0.1:4873/@jest%2fsource-map/-/source-map-25.2.6.tgz#0ef2209514c6d445ebccea1438c55647f22abb4c" - integrity sha512-VuIRZF8M2zxYFGTEhkNSvQkUKafQro4y+mwUxy5ewRqs5N/ynSFUODYp3fy1zCnbCMy1pz3k+u57uCqx8QRSQQ== +"@jest/source-map@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" + integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== dependencies: callsites "^3.0.0" - graceful-fs "^4.2.3" + graceful-fs "^4.2.4" source-map "^0.6.0" -"@jest/test-result@^25.4.0": - version "25.4.0" - resolved "http://127.0.0.1:4873/@jest%2ftest-result/-/test-result-25.4.0.tgz#6f2ec2c8da9981ef013ad8651c1c6f0cb20c6324" - integrity sha512-8BAKPaMCHlL941eyfqhWbmp3MebtzywlxzV+qtngQ3FH+RBqnoSAhNEPj4MG7d2NVUrMOVfrwuzGpVIK+QnMAA== +"@jest/test-result@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== dependencies: - "@jest/console" "^25.4.0" - "@jest/types" "^25.4.0" + "@jest/console" "^26.6.2" + "@jest/types" "^26.6.2" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^25.4.0": - version "25.4.0" - resolved "http://127.0.0.1:4873/@jest%2ftest-sequencer/-/test-sequencer-25.4.0.tgz#2b96f9d37f18dc3336b28e3c8070f97f9f55f43b" - integrity sha512-240cI+nsM3attx2bMp9uGjjHrwrpvxxrZi8Tyqp/cfOzl98oZXVakXBgxODGyBYAy/UGXPKXLvNc2GaqItrsJg== +"@jest/test-sequencer@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" + integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== dependencies: - "@jest/test-result" "^25.4.0" - jest-haste-map "^25.4.0" - jest-runner "^25.4.0" - jest-runtime "^25.4.0" + "@jest/test-result" "^26.6.2" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" -"@jest/transform@^25.4.0": - version "25.4.0" - resolved "http://127.0.0.1:4873/@jest%2ftransform/-/transform-25.4.0.tgz#eef36f0367d639e2fd93dccd758550377fbb9962" - integrity sha512-t1w2S6V1sk++1HHsxboWxPEuSpN8pxEvNrZN+Ud/knkROWtf8LeUmz73A4ezE8476a5AM00IZr9a8FO9x1+j3g== +"@jest/transform@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== dependencies: "@babel/core" "^7.1.0" - "@jest/types" "^25.4.0" + "@jest/types" "^26.6.2" babel-plugin-istanbul "^6.0.0" - chalk "^3.0.0" + chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.3" - jest-haste-map "^25.4.0" - jest-regex-util "^25.2.6" - jest-util "^25.4.0" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-regex-util "^26.0.0" + jest-util "^26.6.2" micromatch "^4.0.2" pirates "^4.0.1" - realpath-native "^2.0.0" slash "^3.0.0" source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/types@^25.4.0": - version "25.4.0" - resolved "http://127.0.0.1:4873/@jest%2ftypes/-/types-25.4.0.tgz#5afeb8f7e1cba153a28e5ac3c9fe3eede7206d59" - integrity sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw== +"@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" "@types/yargs" "^15.0.0" - chalk "^3.0.0" + chalk "^4.0.0" + +"@nodelib/fs.scandir@2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" + integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA== + dependencies: + "@nodelib/fs.stat" "2.0.4" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" + integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" + integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow== + dependencies: + "@nodelib/fs.scandir" "2.1.4" + fastq "^1.6.0" + +"@phc/format@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@phc/format/-/format-1.0.0.tgz#b5627003b3216dc4362125b13f48a4daa76680e4" + integrity sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ== + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== "@sinonjs/commons@^1.7.0": - version "1.7.2" - resolved "http://127.0.0.1:4873/@sinonjs%2fcommons/-/commons-1.7.2.tgz#505f55c74e0272b43f6c52d81946bed7058fc0e2" - integrity sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw== + version "1.8.2" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.2.tgz#858f5c4b48d80778fde4b9d541f27edc0d56488b" + integrity sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw== dependencies: type-detect "4.0.8" -"@types/babel__core@^7.1.7": - version "7.1.7" - resolved "http://127.0.0.1:4873/@types%2fbabel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89" - integrity sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw== +"@sinonjs/fake-timers@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": + version "7.1.12" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d" + integrity sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -456,24 +552,24 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.1" - resolved "http://127.0.0.1:4873/@types%2fbabel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04" - integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew== + version "7.6.2" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.2.tgz#f3d71178e187858f7c45e30380f8f1b7415a12d8" + integrity sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.0.2" - resolved "http://127.0.0.1:4873/@types%2fbabel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" - integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + version "7.4.0" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.0.tgz#0c888dd70b3ee9eebb6e4f200e809da0076262be" + integrity sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.0.10" - resolved "http://127.0.0.1:4873/@types%2fbabel__traverse/-/babel__traverse-7.0.10.tgz#d9a99f017317d9b3d1abc2ced45d3bca68df0daf" - integrity sha512-74fNdUGrWsgIB/V9kTO5FGHPWYY6Eqn+3Z7L6Hc4e/BxjYV7puvBqp5HwsVYYfLm6iURYBNCx4Ut37OF9yitCw== +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.11.0.tgz#b9a1efa635201ba9bc850323a8793ee2d36c04a0" + integrity sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg== dependencies: "@babel/types" "^7.3.0" @@ -485,37 +581,29 @@ "@types/connect" "*" "@types/node" "*" -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "http://127.0.0.1:4873/@types%2fcolor-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/compression@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@types/compression/-/compression-1.7.0.tgz#8dc2a56604873cf0dd4e746d9ae4d31ae77b2390" + integrity sha512-3LzWUM+3k3XdWOUk/RO+uSjv7YWOatYq2QADJntK1pjkk4DfVP0KrIEPDnXRJxAAGKe0VpIPRmlINLDuCedZWw== + dependencies: + "@types/express" "*" -"@types/config@^0.0.36": +"@types/config@^0.0.38": + version "0.0.38" + resolved "https://registry.yarnpkg.com/@types/config/-/config-0.0.38.tgz#ca30679b21b5b297299467e3a3f1c8e2e64b9170" + integrity sha512-z2WizAfIFgSv8SQfQ8c0LlbDAcK47D/o93XW6bxZ9t3bs4fmmfAPjk1nhAIBTG84PBBCHfSPM+8g7vhLdbFokg== + +"@types/connect-flash@^0.0.36": version "0.0.36" - resolved "https://registry.yarnpkg.com/@types/config/-/config-0.0.36.tgz#bf53ca640f3a1a6a2072a9f33e02a44def07a40b" - integrity sha512-EoAeT1MyFWh2BJvBDEFInY714bQBbHOAucqxqqhprhbBFqr+B7fuN5T9CJqUIGDzvwubnKKRqmSo6yPo0aSpNw== - -"@types/connect-flash@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@types/connect-flash/-/connect-flash-0.0.35.tgz#c1bc38750422dac44b6a656b9dac72da17560fb7" - integrity sha512-pwEiJI1gYhH+s6x4+st/TBgf1CPuATADPJi1+2It4Gnckw1pVVdKycRNDyoHwkZGCb/J38vEdOrxnZ4FsOlvWg== + resolved "https://registry.yarnpkg.com/@types/connect-flash/-/connect-flash-0.0.36.tgz#b07ad6f59d00661618c034d1fcdc56766f82fcc7" + integrity sha512-AclFrWyrjYXqJqaBVZhIj5CS/2INVqHgUADuihthX13vIpk8/GrNVEHcIFaeoyJyhfO83agEgPH+z5spSKovGw== dependencies: "@types/express" "*" -"@types/connect-redis@^0.0.13": - version "0.0.13" - resolved "https://registry.yarnpkg.com/@types/connect-redis/-/connect-redis-0.0.13.tgz#9237f7f57b79d9f6418993fd6f3b6ea923859079" - integrity sha512-bHo/UWrUPbWkn05D1YAMs31wG+0dMt6GYXjv8Vfu8kAxO6CfD4N6lmHv/sAkjzYVdXFhc5jck/kEYLBDPJ90iQ== - dependencies: - "@types/express" "*" - "@types/express-session" "*" - "@types/ioredis" "*" - "@types/redis" "*" - "@types/connect@*": - version "3.4.33" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" - integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + version "3.4.34" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901" + integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ== dependencies: "@types/node" "*" @@ -526,93 +614,136 @@ dependencies: "@types/express" "*" -"@types/cookie@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" - integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== +"@types/cookie@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.0.tgz#14f854c0f93d326e39da6e3b6f34f7d37513d108" + integrity sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg== -"@types/express-serve-static-core@*": - version "4.17.5" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.5.tgz#a00ac7dadd746ae82477443e4d480a6a93ea083c" - integrity sha512-578YH5Lt88AKoADy0b2jQGwJtrBxezXtVe/MBqWXKZpqx91SnC0pVkVCcxcytz3lWW+cHBYDi3Ysh0WXc+rAYw== +"@types/cookiejar@*": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8" + integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== + +"@types/express-serve-static-core@^4.17.18": + version "4.17.18" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.18.tgz#8371e260f40e0e1ca0c116a9afcd9426fa094c40" + integrity sha512-m4JTwx5RUBNZvky/JJ8swEJPKFd8si08pPF2PfizYjGZOKr/svUWPcoUmLow6MmPzhasphB7gSTINY67xn3JNA== dependencies: "@types/node" "*" + "@types/qs" "*" "@types/range-parser" "*" -"@types/express-session@*", "@types/express-session@^1.17.0": - version "1.17.0" - resolved "http://127.0.0.1:4873/@types%2fexpress-session/-/express-session-1.17.0.tgz#770daf81368f6278e3e40dd894e1e52abbdca0cd" - integrity sha512-OQEHeBFE1UhChVIBhRh9qElHUvTp4BzKKHxMDkGHT7WuYk5eL93hPG7D8YAIkoBSbhNEY0RjreF15zn+U0eLjA== +"@types/express-session@^1.17.0": + version "1.17.3" + resolved "https://registry.yarnpkg.com/@types/express-session/-/express-session-1.17.3.tgz#4a37c5c4428b8f922ac8ac1cb4bd9190a4d2b097" + integrity sha512-57DnyxiqClXOIjoCgeKCUYfKxBPOlOY/k+l1TPK+7bSwyiPTrS5FIk1Ycql7twk4wO7P5lfOVy6akDGiaMSLfw== dependencies: "@types/express" "*" - "@types/node" "*" "@types/express@*", "@types/express@^4.17.6": - version "4.17.6" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.6.tgz#6bce49e49570507b86ea1b07b806f04697fac45e" - integrity sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w== + version "4.17.11" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545" + integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg== dependencies: "@types/body-parser" "*" - "@types/express-serve-static-core" "*" + "@types/express-serve-static-core" "^4.17.18" "@types/qs" "*" "@types/serve-static" "*" -"@types/ioredis@*": - version "4.14.9" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.14.9.tgz#774387d44d3ad60e1b849044b2b28b96e5813866" - integrity sha512-yNdzppM6vY4DYqXCnt4A3PXArxsMWeJCYxFlyl4AJKrNSGMEAP9TPcXR+8Q6zh9glcCtxmwMQhi4pwdqqHH3OA== +"@types/formidable@^1.0.31": + version "1.0.32" + resolved "https://registry.yarnpkg.com/@types/formidable/-/formidable-1.0.32.tgz#d9a7eefbaa995a4486ec4e3960e9552e68b3f33c" + integrity sha512-jOAB5+GFW+C+2xdvUcpd/CnYg2rD5xCyagJLBJU+9PB4a/DKmsAqS9yZI3j/Q9zwvM7ztPHaAIH1ijzp4cezdQ== + dependencies: + "@types/node" "*" + +"@types/geoip-lite@^1.1.31": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@types/geoip-lite/-/geoip-lite-1.4.1.tgz#2c0d787fb14b2463b244baca1f3b9023fba3c49b" + integrity sha512-qHH5eF3rL1wwqpzdsgMdgskfdWXxxQvJb9POJ66NK7/1l3QXsqHLpIheh9OmhtqZ2CF7AmN0sA2R4PgW8JSm7w== + +"@types/graceful-fs@^4.1.2": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.4.tgz#4ff9f641a7c6d1a3508ff88bc3141b152772e753" + integrity sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg== dependencies: "@types/node" "*" "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.1" - resolved "http://127.0.0.1:4873/@types%2fistanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" - integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== "@types/istanbul-lib-report@*": version "3.0.0" - resolved "http://127.0.0.1:4873/@types%2fistanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + 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@^1.1.1": - version "1.1.1" - resolved "http://127.0.0.1:4873/@types%2fistanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a" - integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA== +"@types/istanbul-reports@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" + integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA== dependencies: - "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" -"@types/jest@^25.2.1": - version "25.2.1" - resolved "http://127.0.0.1:4873/@types%2fjest/-/jest-25.2.1.tgz#9544cd438607955381c1bdbdb97767a249297db5" - integrity sha512-msra1bCaAeEdkSyA0CZ6gW1ukMIvZ5YoJkdXw/qhQdsuuDlFTcEUrUw8CLCPt2rVRUfXlClVvK2gvPs9IokZaA== +"@types/jest@26.x", "@types/jest@^26.0.4": + version "26.0.20" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307" + integrity sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA== dependencies: - jest-diff "^25.2.1" - pretty-format "^25.2.1" + jest-diff "^26.0.0" + pretty-format "^26.0.0" -"@types/mime@*": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" - integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== +"@types/json-schema@^7.0.3": + version "7.0.7" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" + integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== + +"@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/mjml-core@*": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@types/mjml-core/-/mjml-core-4.7.0.tgz#8fc4510ac7927795be1218042222f3dd98cee433" + integrity sha512-sjdnVUQCZMRCXNuIve6OmB/pyoCV0wPbc5UV+VDNE/qTrM5ObJiOGpSVjwh2Kv7AEvPMP3hBh+xB6ERdN/ZPvg== "@types/mjml@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@types/mjml/-/mjml-4.0.4.tgz#af6075d29f64d47186d76125504daf544dfb2b42" - integrity sha512-4PhI6iZ1zGXZ9X9W0bbmI7mS2xdxITURueqSWJ/cTeS5+tbAtOUDG1ww/fPbfcffWwR4NeOjyNcZiczafH/yfw== + version "4.7.0" + resolved "https://registry.yarnpkg.com/@types/mjml/-/mjml-4.7.0.tgz#ea31b58008f54119efda9e673af674757d35981b" + integrity sha512-aWWu8Lxq2SexXGs+lBPRUpN3kFf0sDRo3Y4jz7BQ15cQvMfyZOadgFJsNlHmDqI6D2Qjx0PIK+1f9IMXgq9vTA== + dependencies: + "@types/mjml-core" "*" "@types/mysql@^2.15.10": - version "2.15.10" - resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.10.tgz#225e99e16f6ed3e00091e7cd8821c9fa3cb38149" - integrity sha512-mx8HnU+ob01hT3f4GDW8NSoUqID1CgRfiPh/CgeDgdwvG0DsQtZsPdOXH9LHos/pKv2qkZAA4/ospo0+QoOfUQ== + version "2.15.17" + resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.17.tgz#18b9a64b3c83916e768cf0c1bd7469f7ecbb7484" + integrity sha512-5vlnAFgdjFGqu3fHbd+pp+qL9mMty6c/N65TjsT5H+kfet50Qq4tXWMrD5lm/ftXeiEQwbAndZepB/eaLGaTew== dependencies: "@types/node" "*" +"@types/nanoid@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/nanoid/-/nanoid-2.1.0.tgz#41edfda78986e9127d0dc14de982de766f994020" + integrity sha512-xdkn/oRTA0GSNPLIKZgHWqDTWZsVrieKomxJBOQUK9YDD+zfSgmwD5t4WJYra5S7XyhTw7tfvwznW+pFexaepQ== + dependencies: + "@types/node" "*" + +"@types/node-fetch@^2.5.7": + version "2.5.8" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.8.tgz#e199c835d234c7eb0846f6618012e558544ee2fb" + integrity sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + "@types/node@*": - version "13.13.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.2.tgz#160d82623610db590a64e8ca81784e11117e5a54" - integrity sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A== + version "14.14.22" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.22.tgz#0d29f382472c4ccf3bd96ff0ce47daf5b7b84b18" + integrity sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw== "@types/nodemailer@^6.4.0": version "6.4.0" @@ -623,7 +754,7 @@ "@types/normalize-package-data@^2.4.0": version "2.4.0" - resolved "http://127.0.0.1:4873/@types%2fnormalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== "@types/nunjucks@^3.1.3": @@ -638,81 +769,167 @@ dependencies: "@types/node" "*" -"@types/prettier@^1.19.0": - version "1.19.1" - resolved "http://127.0.0.1:4873/@types%2fprettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" - integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ== +"@types/prettier@^2.0.0": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.6.tgz#f4b1efa784e8db479cdb8b14403e2144b1e9ff03" + integrity sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA== "@types/qs@*": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.1.tgz#937fab3194766256ee09fcd40b781740758617e7" - integrity sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw== + version "6.9.5" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.5.tgz#434711bdd49eb5ee69d90c1d67c354a9a8ecb18b" + integrity sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ== "@types/range-parser@*": version "1.2.3" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/redis@*", "@types/redis@^2.8.18": - version "2.8.18" - resolved "http://127.0.0.1:4873/@types%2fredis/-/redis-2.8.18.tgz#6e95de50d848cd9c0aacb89aa8a6aef07a0a34b3" - integrity sha512-29ffRZITbLRs4zboL31EPJVDhSC/pHommWpf0rRcpwz45fvH6U2VxdRM6wWPSJu23l/kXQNKrMR8SAlLB7OqbQ== +"@types/redis@^2.8.18": + version "2.8.28" + resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.28.tgz#5862b2b64aa7f7cbc76dafd7e6f06992b52c55e3" + integrity sha512-8l2gr2OQ969ypa7hFOeKqtFoY70XkHxISV0pAwmQ2nm6CSPb1brmTmqJCGGrekCo+pAZyWlNXr+Kvo6L/1wijA== dependencies: "@types/node" "*" "@types/serve-static@*": - version "1.13.3" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1" - integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g== + version "1.13.9" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.9.tgz#aacf28a85a05ee29a11fb7c3ead935ac56f33e4e" + integrity sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA== dependencies: - "@types/express-serve-static-core" "*" - "@types/mime" "*" + "@types/mime" "^1" + "@types/node" "*" -"@types/stack-utils@^1.0.1": - version "1.0.1" - resolved "http://127.0.0.1:4873/@types%2fstack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" - integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/stack-utils@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" + integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw== -"@types/uuid@^7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-7.0.2.tgz#d680a9c596ef84abf5c4c07a32ffd66d582526f8" - integrity sha512-8Ly3zIPTnT0/8RCU6Kg/G3uTICf9sRwYOpUzSIM3503tLIKcnJPRuinHhXngJUy2MntrEf6dlpOHXJju90Qh5w== +"@types/superagent@*": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.10.tgz#5e2cc721edf58f64fe9b819f326ee74803adee86" + integrity sha512-xAgkb2CMWUMCyVc/3+7iQfOEBE75NvuZeezvmixbUw3nmENf2tCnQkW5yQLTYqvXUQ+R6EXxdqKKbal2zM5V/g== + dependencies: + "@types/cookiejar" "*" + "@types/node" "*" + +"@types/supertest@^2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.10.tgz#630d79b4d82c73e043e43ff777a9ca98d457cab7" + integrity sha512-Xt8TbEyZTnD5Xulw95GLMOkmjGICrOQyJ2jqgkSjAUR3mm7pAIzSR0NFBaMcwlzVvlpCjNwbATcWWwjNiZiFrQ== + dependencies: + "@types/superagent" "*" + +"@types/uuid@^8.0.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" + integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== "@types/ws@^7.2.4": - version "7.2.4" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.2.4.tgz#b3859f7b9c243b220efac9716ec42c716a72969d" - integrity sha512-9S6Ask71vujkVyeEXKxjBSUV8ZUB0mjL5la4IncBoheu04bDaYyUKErh1BQcY9+WzOUOiKqz/OnpJHYckbMfNg== + version "7.4.0" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.0.tgz#499690ea08736e05a8186113dac37769ab251a0e" + integrity sha512-Y29uQ3Uy+58bZrFLhX36hcI3Np37nqWE7ky5tjiDoy1GDZnIwVxS0CgF+s+1bXMzjKBFy+fqaRfb708iNzdinw== dependencies: "@types/node" "*" "@types/yargs-parser@*": - version "15.0.0" - resolved "http://127.0.0.1:4873/@types%2fyargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" - integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + version "20.2.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" + integrity sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA== "@types/yargs@^15.0.0": - version "15.0.4" - resolved "http://127.0.0.1:4873/@types%2fyargs/-/yargs-15.0.4.tgz#7e5d0f8ca25e9d5849f2ea443cf7c402decd8299" - integrity sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg== + version "15.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.12.tgz#6234ce3e3e3fa32c5db301a170f96a599c960d74" + integrity sha512-f+fD/fQAo3BCbCDlrUpznF1A5Zp9rB0noS5vnoormHSIPFKL0Z2DcUJ3Gxp5ytH4uLRNxy7AwYUC9exZzqGMAw== dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@^4.2.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.14.0.tgz#92db8e7c357ed7d69632d6843ca70b71be3a721d" + integrity sha512-IJ5e2W7uFNfg4qh9eHkHRUCbgZ8VKtGwD07kannJvM5t/GU8P8+24NX8gi3Hf5jST5oWPY8kyV1s/WtfiZ4+Ww== + dependencies: + "@typescript-eslint/experimental-utils" "4.14.0" + "@typescript-eslint/scope-manager" "4.14.0" + debug "^4.1.1" + functional-red-black-tree "^1.0.1" + lodash "^4.17.15" + regexpp "^3.0.0" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/experimental-utils@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.14.0.tgz#5aa7b006736634f588a69ee343ca959cd09988df" + integrity sha512-6i6eAoiPlXMKRbXzvoQD5Yn9L7k9ezzGRvzC/x1V3650rUk3c3AOjQyGYyF9BDxQQDK2ElmKOZRD0CbtdkMzQQ== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/scope-manager" "4.14.0" + "@typescript-eslint/types" "4.14.0" + "@typescript-eslint/typescript-estree" "4.14.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/parser@^4.2.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.14.0.tgz#62d4cd2079d5c06683e9bfb200c758f292c4dee7" + integrity sha512-sUDeuCjBU+ZF3Lzw0hphTyScmDDJ5QVkyE21pRoBo8iDl7WBtVFS+WDN3blY1CH3SBt7EmYCw6wfmJjF0l/uYg== + dependencies: + "@typescript-eslint/scope-manager" "4.14.0" + "@typescript-eslint/types" "4.14.0" + "@typescript-eslint/typescript-estree" "4.14.0" + debug "^4.1.1" + +"@typescript-eslint/scope-manager@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.14.0.tgz#55a4743095d684e1f7b7180c4bac2a0a3727f517" + integrity sha512-/J+LlRMdbPh4RdL4hfP1eCwHN5bAhFAGOTsvE6SxsrM/47XQiPSgF5MDgLyp/i9kbZV9Lx80DW0OpPkzL+uf8Q== + dependencies: + "@typescript-eslint/types" "4.14.0" + "@typescript-eslint/visitor-keys" "4.14.0" + +"@typescript-eslint/types@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.14.0.tgz#d8a8202d9b58831d6fd9cee2ba12f8a5a5dd44b6" + integrity sha512-VsQE4VvpldHrTFuVPY1ZnHn/Txw6cZGjL48e+iBxTi2ksa9DmebKjAeFmTVAYoSkTk7gjA7UqJ7pIsyifTsI4A== + +"@typescript-eslint/typescript-estree@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.0.tgz#4bcd67486e9acafc3d0c982b23a9ab8ac8911ed7" + integrity sha512-wRjZ5qLao+bvS2F7pX4qi2oLcOONIB+ru8RGBieDptq/SudYwshveORwCVU4/yMAd4GK7Fsf8Uq1tjV838erag== + dependencies: + "@typescript-eslint/types" "4.14.0" + "@typescript-eslint/visitor-keys" "4.14.0" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/visitor-keys@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.0.tgz#b1090d9d2955b044b2ea2904a22496849acbdf54" + integrity sha512-MeHHzUyRI50DuiPgV9+LxcM52FCJFYjJiWHtXlbyC27b80mfOwKeiKI+MHOTEpcpfmoPFm/vvQS88bYIx6PZTA== + dependencies: + "@typescript-eslint/types" "4.14.0" + eslint-visitor-keys "^2.0.0" + a-sync-waterfall@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz#75b6b6aa72598b497a125e7a2770f14f4c8a1fa7" integrity sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA== -abab@^2.0.0: - version "2.0.3" - resolved "http://127.0.0.1:4873/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" - integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== +abab@^2.0.3: + 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" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -accepts@~1.3.7: +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== @@ -720,46 +937,88 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-globals@^4.3.2: - version "4.3.4" - resolved "http://127.0.0.1:4873/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" - integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== +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 "^6.0.1" - acorn-walk "^6.0.1" + acorn "^7.1.1" + acorn-walk "^7.1.1" -acorn-walk@^6.0.1: - version "6.2.0" - resolved "http://127.0.0.1:4873/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== +acorn-jsx@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" + integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== -acorn@^6.0.1: - version "6.4.1" - resolved "http://127.0.0.1:4873/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" - integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== +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.0: - version "7.1.1" - resolved "http://127.0.0.1:4873/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" - integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== +acorn@^7.1.1, acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -ajv@^6.5.5: - version "6.12.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" - integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== +addressparser@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746" + integrity sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y= + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + +ajv@^6.10.0, ajv@^6.12.3, 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" +ajv@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.0.3.tgz#13ae747eff125cafb230ac504b2406cf371eece2" + integrity sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-align@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" + integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== + dependencies: + string-width "^3.0.0" + +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-escapes@^4.2.1: version "4.3.1" - resolved "http://127.0.0.1:4873/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== dependencies: type-fest "^0.11.0" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -767,7 +1026,7 @@ ansi-regex@^4.1.0: ansi-regex@^5.0.0: version "5.0.0" - resolved "http://127.0.0.1:4873/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== ansi-styles@^3.2.0, ansi-styles@^3.2.1: @@ -778,16 +1037,15 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: color-convert "^1.9.0" ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.2.1" - resolved "http://127.0.0.1:4873/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: - "@types/color-name" "^1.1.1" color-convert "^2.0.1" anymatch@^2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" @@ -801,48 +1059,76 @@ anymatch@^3.0.3, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + arg@^4.1.0: version "4.1.3" - resolved "http://127.0.0.1:4873/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== +argon2@^0.27.0: + version "0.27.1" + resolved "https://registry.yarnpkg.com/argon2/-/argon2-0.27.1.tgz#4ff1dda0de4f5a2089f373bba5c2c6962e0f0668" + integrity sha512-On68kSinTh4DOlLVCEYgQYpx0yuGRsqU9UwV7jUB26PWv+092r8Uz891KFVEqdsksiDXDhA7kXL4z3in/FBItg== + dependencies: + "@phc/format" "^1.0.0" + node-addon-api "^3.0.2" + node-pre-gyp "^0.17.0" + opencollective-postinstall "^2.0.3" + argparse@^1.0.7: version "1.0.10" - resolved "http://127.0.0.1:4873/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" arr-diff@^4.0.0: version "4.0.0" - resolved "http://127.0.0.1:4873/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= arr-flatten@^1.1.0: version "1.1.0" - resolved "http://127.0.0.1:4873/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== arr-union@^3.1.0: version "3.1.0" - resolved "http://127.0.0.1:4873/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-equal@^1.0.0: - version "1.0.0" - resolved "http://127.0.0.1:4873/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= - 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== + array-unique@^0.3.2: version "0.3.2" - resolved "http://127.0.0.1:4873/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== + asap@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -862,13 +1148,25 @@ assert-plus@1.0.0, assert-plus@^1.0.0: assign-symbols@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -astral-regex@^1.0.0: - version "1.0.0" - resolved "http://127.0.0.1:4873/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^2.1.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" async@^3.1.0: version "3.2.0" @@ -882,7 +1180,7 @@ asynckit@^0.4.0: atob@^2.1.2: version "2.1.2" - resolved "http://127.0.0.1:4873/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== aws-sign2@~0.7.0: @@ -891,26 +1189,27 @@ aws-sign2@~0.7.0: integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" - integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -babel-jest@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/babel-jest/-/babel-jest-25.4.0.tgz#409eb3e2ddc2ad9a92afdbb00991f1633f8018d0" - integrity sha512-p+epx4K0ypmHuCnd8BapfyOwWwosNCYhedetQey1awddtfmEX0MmdxctGl956uwUmjwXR5VSS5xJcGX9DvdIog== +babel-jest@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== dependencies: - "@jest/transform" "^25.4.0" - "@jest/types" "^25.4.0" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" "@types/babel__core" "^7.1.7" babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^25.4.0" - chalk "^3.0.0" + babel-preset-jest "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" slash "^3.0.0" babel-plugin-istanbul@^6.0.0: version "6.0.0" - resolved "http://127.0.0.1:4873/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -919,21 +1218,25 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.4.0.tgz#0c122c1b93fb76f52d2465be2e8069e798e9d442" - integrity sha512-M3a10JCtTyKevb0MjuH6tU+cP/NVQZ82QPADqI1RQYY1OphztsCeIeQmTsHmF/NS6m0E51Zl4QNsI3odXSQF5w== +babel-plugin-jest-hoist@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== 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@^0.1.2: - version "0.1.2" - resolved "http://127.0.0.1:4873/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz#fb4a4c51fe38ca60fede1dc74ab35eb843cb41d6" - integrity sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw== +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" @@ -941,31 +1244,44 @@ babel-preset-current-node-syntax@^0.1.2: "@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@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/babel-preset-jest/-/babel-preset-jest-25.4.0.tgz#10037cc32b751b994b260964629e49dc479abf4c" - integrity sha512-PwFiEWflHdu3JCeTr0Pb9NcHHE34qWFnPQRVPvqQITx4CsDCzs6o05923I10XvLvn9nNsRHuiVgB72wG/90ZHQ== +babel-preset-jest@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== dependencies: - babel-plugin-jest-hoist "^25.4.0" - babel-preset-current-node-syntax "^0.1.2" + babel-plugin-jest-hoist "^26.6.2" + babel-preset-current-node-syntax "^1.0.0" -babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base32.js@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base32.js/-/base32.js-0.1.0.tgz#b582dec693c2f11e893cf064ee6ac5b6131a2202" + integrity sha1-tYLexpPC8R6JPPBk7mrFthMaIgI= + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= + base@^0.11.1: version "0.11.2" - resolved "http://127.0.0.1:4873/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" @@ -983,15 +1299,27 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= + dependencies: + callsite "1.0.0" + bignumber.js@9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== binary-extensions@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" - integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== body-parser@1.19.0: version "1.19.0" @@ -1009,11 +1337,25 @@ body-parser@1.19.0: raw-body "2.4.0" type-is "~1.6.17" -boolbase@~1.0.0: +boolbase@^1.0.0, boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= +boxen@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" + integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^5.3.1" + chalk "^3.0.0" + cli-boxes "^2.2.0" + string-width "^4.1.0" + term-size "^2.1.0" + type-fest "^0.8.1" + widest-line "^3.1.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1024,7 +1366,7 @@ brace-expansion@^1.1.7: braces@^2.3.1: version "2.3.2" - resolved "http://127.0.0.1:4873/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" @@ -1047,35 +1389,38 @@ braces@^3.0.1, braces@~3.0.2: browser-process-hrtime@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browser-resolve@^1.11.3: - version "1.11.3" - resolved "http://127.0.0.1:4873/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - dependencies: - resolve "1.1.7" - bs-logger@0.x: version "0.2.6" - resolved "http://127.0.0.1:4873/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + 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 "http://127.0.0.1:4873/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + 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-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" - resolved "http://127.0.0.1:4873/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -1083,7 +1428,7 @@ bytes@3.1.0: cache-base@^1.0.1: version "1.0.1" - resolved "http://127.0.0.1:4873/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" @@ -1096,12 +1441,30 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + callsites@^3.0.0: version "3.1.0" - resolved "http://127.0.0.1:4873/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camel-case@3.0.x: +camel-case@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= @@ -1114,9 +1477,14 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + capture-exit@^2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== dependencies: rsvp "^4.8.4" @@ -1137,38 +1505,65 @@ chalk@^2.0.0, chalk@^2.4.2: chalk@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" -cheerio@^0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" - integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4= +chalk@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + 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== + +cheerio-select-tmp@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/cheerio-select-tmp/-/cheerio-select-tmp-0.1.1.tgz#55bbef02a4771710195ad736d5e346763ca4e646" + integrity sha512-YYs5JvbpU19VYJyj+F7oYrIE2BOll1/hRU7rEy/5+v9BzkSo3bK81iAeeQEMI92vRIxz677m72UmJUiVwwgjfQ== + dependencies: + css-select "^3.1.2" + css-what "^4.0.0" + domelementtype "^2.1.0" + domhandler "^4.0.0" + domutils "^2.4.4" + +cheerio@1.0.0-rc.3: + version "1.0.0-rc.3" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6" + integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA== dependencies: css-select "~1.2.0" - dom-serializer "~0.1.0" + dom-serializer "~0.1.1" entities "~1.1.1" htmlparser2 "^3.9.1" - lodash.assignin "^4.0.9" - lodash.bind "^4.1.4" - lodash.defaults "^4.0.1" - lodash.filter "^4.4.0" - lodash.flatten "^4.2.0" - lodash.foreach "^4.3.0" - lodash.map "^4.4.0" - lodash.merge "^4.4.0" - lodash.pick "^4.2.1" - lodash.reduce "^4.4.0" - lodash.reject "^4.4.0" - lodash.some "^4.4.0" + lodash "^4.15.0" + parse5 "^3.0.1" -chokidar@^3.0.0, chokidar@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" - integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== +cheerio@^1.0.0-rc.3: + version "1.0.0-rc.5" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.5.tgz#88907e1828674e8f9fee375188b27dadd4f0fa2f" + integrity sha512-yoqps/VCaZgN4pfXtenwHROTp8NG6/Hlt4Jpz2FEP0ZJQ+ZUkVDd0hAPDNKhj3nakpfPt/CNs57yEtxD1bXQiw== + dependencies: + cheerio-select-tmp "^0.1.0" + dom-serializer "~1.2.0" + domhandler "^4.0.0" + entities "~2.1.0" + htmlparser2 "^6.0.0" + parse5 "^6.0.0" + parse5-htmlparser2-tree-adapter "^6.0.0" + +chokidar@^3.0.0, chokidar@^3.2.2, chokidar@^3.3.0: + version "3.5.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" + integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -1176,18 +1571,28 @@ chokidar@^3.0.0, chokidar@^3.3.0: is-binary-path "~2.1.0" is-glob "~4.0.1" normalize-path "~3.0.0" - readdirp "~3.3.0" + readdirp "~3.5.0" optionalDependencies: - fsevents "~2.1.2" + fsevents "~2.3.1" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== ci-info@^2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +cjs-module-lexer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" + integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== + class-utils@^0.3.5: version "0.3.6" - resolved "http://127.0.0.1:4873/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" @@ -1195,13 +1600,18 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -clean-css@4.2.x: +clean-css@^4.2.1: version "4.2.3" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== dependencies: source-map "~0.6.0" +cli-boxes@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== + cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -1213,26 +1623,47 @@ cliui@^5.0.0: cliui@^6.0.0: version "6.0.0" - resolved "http://127.0.0.1:4873/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== dependencies: string-width "^4.2.0" strip-ansi "^6.0.0" wrap-ansi "^6.2.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" + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + co@^4.6.0: version "4.6.0" - resolved "http://127.0.0.1:4873/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + collect-v8-coverage@^1.0.0: version "1.0.1" - resolved "http://127.0.0.1:4873/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== collection-visit@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" @@ -1247,7 +1678,7 @@ color-convert@^1.9.0: color-convert@^2.0.1: version "2.0.1" - resolved "http://127.0.0.1:4873/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + 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" @@ -1259,46 +1690,91 @@ color-name@1.1.3: color-name@~1.1.4: version "1.1.4" - resolved "http://127.0.0.1:4873/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -combined-stream@^1.0.6, combined-stream@~1.0.6: +colors@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" -commander@2.17.x: - version "2.17.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" - integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== - -commander@^2.11.0, commander@^2.15.1, commander@^2.19.0: +commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" - integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== +commander@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== -commander@~2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= -component-emitter@^1.2.1: +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +component-emitter@^1.2.1, component-emitter@^1.3.0, component-emitter@~1.3.0: version "1.3.0" - resolved "http://127.0.0.1:4873/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + 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= +concurrently@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-5.3.0.tgz#7500de6410d043c912b2da27de3202cb489b1e7b" + integrity sha512-8MhqOB6PWlBfA2vJ8a0bSFKATOdWlHiQlk11IfmQBPaHVP8oP2gsh2MObE6UR3hqDHqvaIvLTyceNW6obVuFHQ== + dependencies: + chalk "^2.4.2" + date-fns "^2.0.1" + lodash "^4.17.15" + read-pkg "^4.0.1" + rxjs "^6.5.2" + spawn-command "^0.0.2-1" + supports-color "^6.1.0" + tree-kill "^1.2.2" + yargs "^13.3.0" + config-chain@^1.1.12: version "1.1.12" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" @@ -1308,21 +1784,33 @@ config-chain@^1.1.12: proto-list "~1.2.1" config@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/config/-/config-3.3.1.tgz#b6a70e2908a43b98ed20be7e367edf0cc8ed5a19" - integrity sha512-+2/KaaaAzdwUBE3jgZON11L1ggLLhpf2FsGrfqYFHZW22ySGv/HqYIXrBwKKvn+XZh1UBUjHwAcrfsSkSygT+Q== + version "3.3.3" + resolved "https://registry.yarnpkg.com/config/-/config-3.3.3.tgz#d3c110fce543022c2fde28712e4f1b8440dee101" + integrity sha512-T3RmZQEAji5KYqUQpziWtyGJFli6Khz7h0rpxDwYNjSkr5ynyTWwO7WpfjHzTXclNCDfSWQRcwMb+NwxJesCKw== dependencies: json5 "^2.1.1" +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + connect-flash@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/connect-flash/-/connect-flash-0.1.1.tgz#d8630f26d95a7f851f9956b1e8cc6732f3b6aa30" integrity sha1-2GMPJtlaf4UfmVax6MxnMvO2qjA= -connect-redis@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/connect-redis/-/connect-redis-4.0.4.tgz#b194abe2f3754551f38086e1a28cb9e68d6c3b28" - integrity sha512-aXk7btMlG0J5LqtPNRpFKa5fglzlTzukYNx+Fq8cghbUIQHN/gyK9c3+b0XEROMwiSxMoZDADqjp9tdpUoZLAg== +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.3: version "0.5.3" @@ -1338,7 +1826,7 @@ content-type@~1.0.4: convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.7.0" - resolved "http://127.0.0.1:4873/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== dependencies: safe-buffer "~5.1.1" @@ -1356,6 +1844,11 @@ cookie-signature@1.0.6: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + cookie@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" @@ -1366,22 +1859,35 @@ cookie@^0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== +cookiejar@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" + integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + copy-descriptor@^0.1.0: version "0.1.1" - resolved "http://127.0.0.1:4873/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js@^2.4.0: - version "2.6.11" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" - integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== - core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cross-spawn@^6.0.0, cross-spawn@^6.0.5: +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@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -1392,15 +1898,31 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0: - version "7.0.2" - resolved "http://127.0.0.1:4873/cross-spawn/-/cross-spawn-7.0.2.tgz#d0d7dcfa74e89115c7619f4f721a94e1fdb716d6" - integrity sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw== +cross-spawn@^7.0.0, 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" +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +css-select@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8" + integrity sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA== + dependencies: + boolbase "^1.0.0" + css-what "^4.0.0" + domhandler "^4.0.0" + domutils "^2.4.3" + nth-check "^2.0.0" + css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" @@ -1416,20 +1938,25 @@ css-what@2.1: resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== -cssom@^0.4.1: +css-what@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233" + integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A== + +cssom@^0.4.4: version "0.4.4" - resolved "http://127.0.0.1:4873/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + 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 "http://127.0.0.1:4873/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssstyle@^2.0.0: - version "2.2.0" - resolved "http://127.0.0.1:4873/cssstyle/-/cssstyle-2.2.0.tgz#e4c44debccd6b7911ed617a4395e5754bba59992" - integrity sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA== +cssstyle@^2.2.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" @@ -1440,22 +1967,19 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -data-urls@^1.1.0: - version "1.1.0" - resolved "http://127.0.0.1:4873/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" - integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== - dependencies: - abab "^2.0.0" - whatwg-mimetype "^2.2.0" - whatwg-url "^7.0.0" - -datauri@^2.0.0: +data-urls@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/datauri/-/datauri-2.0.0.tgz#ff0ee23729935a6bcc81f301621bed3e692bf3c7" - integrity sha512-zS2HSf9pI5XPlNZgIqJg/wCJpecgU/HA6E/uv2EfaWnW1EiTGLfy/EexTIsC9c99yoCOTXlqeeWk4FkCSuO3/g== + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== dependencies: - image-size "^0.7.3" - mimer "^1.0.0" + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +date-fns@^2.0.1: + version "2.16.1" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b" + integrity sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ== debug@2.6.9, debug@^2.2.0, debug@^2.3.3: version "2.6.9" @@ -1464,9 +1988,30 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^4.1.0, debug@^4.1.1: +debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + +debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@~4.1.0: version "4.1.1" - resolved "http://127.0.0.1:4873/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" @@ -1476,43 +2021,60 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decimal.js@^10.2.0: + version "10.2.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" + integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw== + decode-uri-component@^0.2.0: version "0.2.0" - resolved "http://127.0.0.1:4873/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@~0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.3" - resolved "http://127.0.0.1:4873/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= deepmerge@^4.2.2: version "4.2.2" - resolved "http://127.0.0.1:4873/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + define-property@^0.2.5: version "0.2.5" - resolved "http://127.0.0.1:4873/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" - resolved "http://127.0.0.1:4873/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" @@ -1523,10 +2085,15 @@ delayed-stream@~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" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + denque@^1.4.1: - version "1.4.1" - resolved "http://127.0.0.1:4873/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf" - integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ== + version "1.5.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.0.tgz#773de0686ff2d8ec2ff92914316a47b73b1c73de" + integrity sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ== depd@~1.1.2: version "1.1.2" @@ -1535,7 +2102,7 @@ depd@~1.1.2: depd@~2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== destroy@~1.0.4: @@ -1543,22 +2110,46 @@ 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= + detect-newline@^3.0.0: version "3.1.0" - resolved "http://127.0.0.1:4873/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^25.2.6: - version "25.2.6" - resolved "http://127.0.0.1:4873/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" - integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== +detect-node@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== diff@^4.0.1: version "4.0.2" - resolved "http://127.0.0.1:4873/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -dom-serializer@0, dom-serializer@^0.2.1: +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" + +dom-serializer@0: version "0.2.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== @@ -1566,7 +2157,16 @@ dom-serializer@0, dom-serializer@^0.2.1: domelementtype "^2.0.1" entities "^2.0.0" -dom-serializer@~0.1.0: +dom-serializer@^1.0.1, dom-serializer@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.2.0.tgz#3433d9136aeb3c627981daa385fc7f32d27c48f1" + integrity sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + entities "^2.0.0" + +dom-serializer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== @@ -1579,17 +2179,17 @@ domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== -domelementtype@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" - integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== +domelementtype@^2.0.1, domelementtype@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.1.0.tgz#a851c080a6d1c3d94344aed151d99f669edf585e" + integrity sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w== -domexception@^1.0.1: - version "1.0.1" - resolved "http://127.0.0.1:4873/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== +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 "^4.0.2" + webidl-conversions "^5.0.0" domhandler@^2.3.0: version "2.4.2" @@ -1599,12 +2199,19 @@ domhandler@^2.3.0: domelementtype "1" domhandler@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.0.0.tgz#51cd13efca31da95bbb0c5bee3a48300e333b3e9" - integrity sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw== + version "3.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-3.3.0.tgz#6db7ea46e4617eb15cf875df68b2b8524ce0037a" + integrity sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA== dependencies: domelementtype "^2.0.1" +domhandler@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.0.0.tgz#01ea7821de996d85f69029e81fa873c21833098e" + integrity sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA== + dependencies: + domelementtype "^2.1.0" + domutils@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" @@ -1621,14 +2228,26 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" -domutils@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.0.0.tgz#15b8278e37bfa8468d157478c58c367718133c08" - integrity sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg== +domutils@^2.0.0, domutils@^2.4.3, domutils@^2.4.4: + version "2.4.4" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.4.4.tgz#282739c4b150d022d34699797369aad8d19bbbd3" + integrity sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA== dependencies: - dom-serializer "^0.2.1" + dom-serializer "^1.0.1" domelementtype "^2.0.1" - domhandler "^3.0.0" + domhandler "^4.0.0" + +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= ecc-jsbn@~0.1.1: version "0.1.2" @@ -1653,6 +2272,11 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= +emittery@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -1660,7 +2284,7 @@ emoji-regex@^7.0.1: emoji-regex@^8.0.0: version "8.0.0" - resolved "http://127.0.0.1:4873/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== encodeurl@~1.0.2: @@ -1670,42 +2294,114 @@ encodeurl@~1.0.2: end-of-stream@^1.1.0: version "1.4.4" - resolved "http://127.0.0.1:4873/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" +engine.io-client@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" + integrity sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.3.2.tgz#18cbc8b6f36e9461c5c0f81df2b830de16058a59" + integrity sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w== + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~6.1.0" + +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" + entities@^1.1.1, entities@~1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== entities@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" - integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" + integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== error-ex@^1.3.1: version "1.3.2" - resolved "http://127.0.0.1:4873/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" +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-goat@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" + integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== + +escape-goat@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-3.0.0.tgz#e8b5fb658553fe8a3c4959c316c6ebb8c842b19c" + integrity sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw== + 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@^1.0.5: +escape-string-regexp@^1.0.5, 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= -escodegen@^1.11.1: - version "1.14.1" - resolved "http://127.0.0.1:4873/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" - integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== +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== + +escodegen@^1.14.1: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== dependencies: esprima "^4.0.1" estraverse "^4.2.0" @@ -1714,19 +2410,115 @@ escodegen@^1.11.1: optionalDependencies: source-map "~0.6.1" +eslint-scope@^5.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-utils@^2.0.0, eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" + integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== + +eslint@^7.9.0: + version "7.18.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.18.0.tgz#7fdcd2f3715a41fe6295a16234bd69aed2c75e67" + integrity sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^0.3.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.2.0" + esutils "^2.0.2" + file-entry-cache "^6.0.0" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.20" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.4" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" - resolved "http://127.0.0.1:4873/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -estraverse@^4.2.0: +esquery@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: version "4.3.0" - resolved "http://127.0.0.1:4873/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + 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, estraverse@^4.2.0: + 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.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + esutils@^2.0.2: version "2.0.3" - resolved "http://127.0.0.1:4873/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== etag@~1.8.1: @@ -1736,12 +2528,12 @@ etag@~1.8.1: exec-sh@^0.3.2: version "0.3.4" - resolved "http://127.0.0.1:4873/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== execa@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== dependencies: cross-spawn "^6.0.0" @@ -1752,10 +2544,10 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^3.2.0: - version "3.4.0" - resolved "http://127.0.0.1:4873/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" - integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== +execa@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== dependencies: cross-spawn "^7.0.0" get-stream "^5.0.0" @@ -1764,18 +2556,17 @@ execa@^3.2.0: merge-stream "^2.0.0" npm-run-path "^4.0.0" onetime "^5.1.0" - p-finally "^2.0.0" signal-exit "^3.0.2" strip-final-newline "^2.0.0" exit@^0.1.2: version "0.1.2" - resolved "http://127.0.0.1:4873/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= expand-brackets@^2.1.4: version "2.1.4" - resolved "http://127.0.0.1:4873/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" @@ -1786,21 +2577,21 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expect@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/expect/-/expect-25.4.0.tgz#0b16c17401906d1679d173e59f0d4580b22f8dc8" - integrity sha512-7BDIX99BTi12/sNGJXA9KMRcby4iAmu1xccBOhyKCyEhjcVKS3hPmHdA/4nSI9QGIOkUropKqr3vv7WMDM5lvQ== +expect@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== dependencies: - "@jest/types" "^25.4.0" + "@jest/types" "^26.6.2" ansi-styles "^4.0.0" - jest-get-type "^25.2.6" - jest-matcher-utils "^25.4.0" - jest-message-util "^25.4.0" - jest-regex-util "^25.2.6" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" express-session@^1.17.1: version "1.17.1" - resolved "http://127.0.0.1:4873/express-session/-/express-session-1.17.1.tgz#36ecbc7034566d38c8509885c044d461c11bf357" + resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.1.tgz#36ecbc7034566d38c8509885c044d461c11bf357" integrity sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q== dependencies: cookie "0.4.0" @@ -1850,27 +2641,27 @@ express@^4.17.1: extend-shallow@^2.0.1: version "2.0.1" - resolved "http://127.0.0.1:4873/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" - resolved "http://127.0.0.1:4873/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: +extend@~3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== extglob@^2.0.4: version "2.0.4" - resolved "http://127.0.0.1:4873/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" @@ -1893,30 +2684,68 @@ extsprintf@^1.2.0: integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= fast-deep-equal@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" - integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + 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-glob@^3.1.1: + version "3.2.5" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" + integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" 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 "http://127.0.0.1:4873/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-safe-stringify@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" + integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== + +fastq@^1.6.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.10.0.tgz#74dbefccade964932cdf500473ef302719c652bb" + integrity sha512-NL2Qc5L3iQEsyYzweq7qfgy5OtXCmGzGvhElGEd/SoFWEMOEczNh5s5ocaF01HDetxz+p8ecjNPA6cZxxIHmzA== + dependencies: + reusify "^1.0.4" + fb-watchman@^2.0.0: version "2.0.1" - resolved "http://127.0.0.1:4873/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== dependencies: bser "2.1.1" +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + +file-entry-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a" + integrity sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA== + dependencies: + flat-cache "^3.0.4" + fill-range@^4.0.0: version "4.0.0" - resolved "http://127.0.0.1:4873/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" @@ -1953,15 +2782,28 @@ find-up@^3.0.0: find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" - resolved "http://127.0.0.1:4873/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + 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" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" + integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== + for-in@^1.0.2: version "1.0.2" - resolved "http://127.0.0.1:4873/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= forever-agent@~0.6.1: @@ -1969,6 +2811,15 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" + integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -1978,6 +2829,11 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +formidable@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" + integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -1985,7 +2841,7 @@ forwarded@~0.1.2: fragment-cache@^0.2.1: version "0.2.1" - resolved "http://127.0.0.1:4873/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" @@ -1995,43 +2851,92 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= +fs-minipass@^1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + 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.1.2, fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== +fsevents@^2.1.2, fsevents@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.1.tgz#b209ab14c61012636c8863507edf7fb68cc54e9f" + integrity sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw== + +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= + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "http://127.0.0.1:4873/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + 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.1: +geoip-lite@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/geoip-lite/-/geoip-lite-1.4.2.tgz#f41dc50086cce3bc31a6d2d578cad1c37f9f17b3" + integrity sha512-1rUNqar68+ldSSlSMdpLZPAM+NRokIDzB2lpQFRHSOaDVqtmy25jTAWe0lM2GqWFeaA35RiLhF8GF0vvL+qOKA== + dependencies: + async "^2.1.1" + colors "^1.1.2" + iconv-lite "^0.4.13" + ip-address "^5.8.9" + lazy "^1.0.11" + rimraf "^2.5.2" + yauzl "^2.9.2" + +get-caller-file@^2.0.1, 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-stream@^4.0.0: +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^4.0.0, get-stream@^4.1.0: version "4.1.0" - resolved "http://127.0.0.1:4873/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== dependencies: pump "^3.0.0" -get-stream@^5.0.0: - version "5.1.0" - resolved "http://127.0.0.1:4873/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" - integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== +get-stream@^5.0.0, get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== dependencies: pump "^3.0.0" get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" - resolved "http://127.0.0.1:4873/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= getpass@^0.1.1: @@ -2041,7 +2946,7 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob-parent@~5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== @@ -2060,19 +2965,62 @@ glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +global-dirs@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" + integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== + dependencies: + ini "1.3.7" + globals@^11.1.0: version "11.12.0" - resolved "http://127.0.0.1:4873/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -graceful-fs@^4.2.3: - version "4.2.3" - resolved "http://127.0.0.1:4873/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +globby@^11.0.1: + version "11.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" + integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== growly@^1.3.0: version "1.3.0" - resolved "http://127.0.0.1:4873/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= har-schema@^2.0.0: @@ -2081,13 +3029,25 @@ har-schema@^2.0.0: integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== dependencies: - ajv "^6.5.5" + ajv "^6.12.3" har-schema "^2.0.0" +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -2095,12 +3055,17 @@ has-flag@^3.0.0: has-flag@^4.0.0: version "4.0.0" - resolved "http://127.0.0.1:4873/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + has-value@^0.3.1: version "0.3.1" - resolved "http://127.0.0.1:4873/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" @@ -2109,7 +3074,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" @@ -2118,53 +3083,65 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" - resolved "http://127.0.0.1:4873/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= has-values@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" kind-of "^4.0.0" -he@1.2.x: +has-yarn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" + integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== + +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" + +he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== hosted-git-info@^2.1.4: version "2.8.8" - resolved "http://127.0.0.1:4873/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "http://127.0.0.1:4873/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== +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.1" + whatwg-encoding "^1.0.5" html-escaper@^2.0.0: version "2.0.2" - resolved "http://127.0.0.1:4873/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -html-minifier@^3.5.3: - version "3.5.21" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" - integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== +html-minifier@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56" + integrity sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig== dependencies: - camel-case "3.0.x" - clean-css "4.2.x" - commander "2.17.x" - he "1.2.x" - param-case "2.1.x" - relateurl "0.2.x" - uglify-js "3.4.x" + camel-case "^3.0.0" + clean-css "^4.2.1" + commander "^2.19.0" + he "^1.2.0" + param-case "^2.1.1" + relateurl "^0.2.7" + uglify-js "^3.5.1" -htmlparser2@^3.9.1, htmlparser2@^3.9.2: +htmlparser2@^3.9.1: version "3.10.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== @@ -2176,7 +3153,7 @@ htmlparser2@^3.9.1, htmlparser2@^3.9.2: inherits "^2.0.1" readable-stream "^3.1.1" -htmlparser2@^4.0.0: +htmlparser2@^4.0.0, htmlparser2@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-4.1.0.tgz#9a4ef161f2e4625ebf7dfbe6c0a2f52d18a59e78" integrity sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q== @@ -2186,6 +3163,21 @@ htmlparser2@^4.0.0: domutils "^2.0.0" entities "^2.0.0" +htmlparser2@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.0.0.tgz#c2da005030390908ca4c91e5629e418e0665ac01" + integrity sha512-numTQtDZMoh78zJpaNdJ9MXb2cv5G3jwUoe3dMQODubZvLoGvTE/Ofp6sHvH8OGKcN/8A47pGLi/k58xHP/Tfw== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.0.0" + domutils "^2.4.4" + entities "^2.0.0" + +http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + http-errors@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" @@ -2219,24 +3211,54 @@ http-signature@~1.2.0: human-signals@^1.1.1: version "1.1.1" - resolved "http://127.0.0.1:4873/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -iconv-lite@0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.13, iconv-lite@^0.4.4, 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" -image-size@^0.7.3: - version "0.7.5" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.7.5.tgz#269f357cf5797cb44683dfa99790e54c705ead04" - integrity sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g== +ignore-by-default@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= + +ignore-walk@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" + integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== + dependencies: + minimatch "^3.0.4" + +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.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +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" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= import-local@^3.0.2: version "3.0.2" - resolved "http://127.0.0.1:4873/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== dependencies: pkg-dir "^4.2.0" @@ -2244,9 +3266,14 @@ import-local@^3.0.2: imurmurhash@^0.1.4: version "0.1.4" - resolved "http://127.0.0.1:4873/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -2265,14 +3292,28 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== +ini@1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" + integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== + +ini@^1.3.4, ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +ip-address@^5.8.9: + version "5.9.4" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-5.9.4.tgz#4660ac261ad61bd397a860a007f7e98e4eaee386" + integrity sha512-dHkI3/YNJq4b/qQaz+c8LuarD3pY24JqZWfjB8aZx1gtpc2MDILu9L9jpZe1sHpzo/yWFweQVn+U//FhazUxmw== + dependencies: + jsbn "1.1.0" + lodash "^4.17.15" + sprintf-js "1.1.2" ip-regex@^2.1.0: version "2.1.0" - resolved "http://127.0.0.1:4873/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= ipaddr.js@1.9.1: @@ -2280,23 +3321,28 @@ ipaddr.js@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== +ipv6-normalize@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz#1b3258290d365fa83239e89907dde4592e7620a8" + integrity sha1-GzJYKQ02X6gyOeiZB93kWS52IKg= + is-accessor-descriptor@^0.1.6: version "0.1.6" - resolved "http://127.0.0.1:4873/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" - resolved "http://127.0.0.1:4873/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-binary-path@~2.1.0: @@ -2308,33 +3354,40 @@ is-binary-path@~2.1.0: is-buffer@^1.1.5: version "1.1.6" - resolved "http://127.0.0.1:4873/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== is-ci@^2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== dependencies: ci-info "^2.0.0" +is-core-module@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" + integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== + dependencies: + has "^1.0.3" + is-data-descriptor@^0.1.4: version "0.1.4" - resolved "http://127.0.0.1:4873/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" is-descriptor@^0.1.0: version "0.1.6" - resolved "http://127.0.0.1:4873/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" @@ -2343,21 +3396,26 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" - resolved "http://127.0.0.1:4873/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" kind-of "^6.0.2" +is-docker@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" + integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" - resolved "http://127.0.0.1:4873/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extendable@^1.0.1: version "1.0.1" - resolved "http://127.0.0.1:4873/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== dependencies: is-plain-object "^2.0.4" @@ -2367,6 +3425,13 @@ is-extglob@^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@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -2374,24 +3439,37 @@ is-fullwidth-code-point@^2.0.0: is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + 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 "http://127.0.0.1:4873/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + 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.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== dependencies: is-extglob "^2.1.1" +is-installed-globally@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" + integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== + dependencies: + global-dirs "^2.0.1" + is-path-inside "^3.0.1" + +is-npm@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" + integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== + is-number@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" @@ -2401,21 +3479,36 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-inside@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" + integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== + is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" - resolved "http://127.0.0.1:4873/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" +is-potential-custom-element-name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" + integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= + is-stream@^1.1.0: version "1.1.0" - resolved "http://127.0.0.1:4873/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-stream@^2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== is-typedarray@^1.0.0, is-typedarray@~1.0.0: @@ -2425,19 +3518,36 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: is-windows@^1.0.2: version "1.0.2" - resolved "http://127.0.0.1:4873/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^2.1.1: - version "2.1.1" - resolved "http://127.0.0.1:4873/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" - integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +is-yarn-global@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" + integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -2445,14 +3555,14 @@ isexe@^2.0.0: isobject@^2.0.0: version "2.1.0" - resolved "http://127.0.0.1:4873/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" - resolved "http://127.0.0.1:4873/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isstream@~0.1.2: @@ -2462,25 +3572,22 @@ isstream@~0.1.2: istanbul-lib-coverage@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== -istanbul-lib-instrument@^4.0.0: - version "4.0.1" - resolved "http://127.0.0.1:4873/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" - integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== +istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== dependencies: "@babel/core" "^7.7.5" - "@babel/parser" "^7.7.5" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" "@istanbuljs/schema" "^0.1.2" istanbul-lib-coverage "^3.0.0" semver "^6.3.0" istanbul-lib-report@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + 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" @@ -2489,7 +3596,7 @@ istanbul-lib-report@^3.0.0: istanbul-lib-source-maps@^4.0.0: version "4.0.0" - resolved "http://127.0.0.1:4873/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== dependencies: debug "^4.1.1" @@ -2498,447 +3605,491 @@ istanbul-lib-source-maps@^4.0.0: istanbul-reports@^3.0.2: version "3.0.2" - resolved "http://127.0.0.1:4873/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-changed-files/-/jest-changed-files-25.4.0.tgz#e573db32c2fd47d2b90357ea2eda0622c5c5cbd6" - integrity sha512-VR/rfJsEs4BVMkwOTuStRyS630fidFVekdw/lBaBQjx9KK3VZFOZ2c0fsom2fRp8pMCrCTP6LGna00o/DXGlqA== +jest-changed-files@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" + integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== dependencies: - "@jest/types" "^25.4.0" - execa "^3.2.0" + "@jest/types" "^26.6.2" + execa "^4.0.0" throat "^5.0.0" -jest-cli@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-cli/-/jest-cli-25.4.0.tgz#5dac8be0fece6ce39f0d671395a61d1357322bab" - integrity sha512-usyrj1lzCJZMRN1r3QEdnn8e6E6yCx/QN7+B1sLoA68V7f3WlsxSSQfy0+BAwRiF4Hz2eHauf11GZG3PIfWTXQ== +jest-cli@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== dependencies: - "@jest/core" "^25.4.0" - "@jest/test-result" "^25.4.0" - "@jest/types" "^25.4.0" - chalk "^3.0.0" + "@jest/core" "^26.6.3" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" exit "^0.1.2" + graceful-fs "^4.2.4" import-local "^3.0.2" is-ci "^2.0.0" - jest-config "^25.4.0" - jest-util "^25.4.0" - jest-validate "^25.4.0" + jest-config "^26.6.3" + jest-util "^26.6.2" + jest-validate "^26.6.2" prompts "^2.0.1" - realpath-native "^2.0.0" - yargs "^15.3.1" + yargs "^15.4.1" -jest-config@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-config/-/jest-config-25.4.0.tgz#56e5df3679a96ff132114b44fb147389c8c0a774" - integrity sha512-egT9aKYxMyMSQV1aqTgam0SkI5/I2P9qrKexN5r2uuM2+68ypnc+zPGmfUxK7p1UhE7dYH9SLBS7yb+TtmT1AA== +jest-config@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== dependencies: "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^25.4.0" - "@jest/types" "^25.4.0" - babel-jest "^25.4.0" - chalk "^3.0.0" + "@jest/test-sequencer" "^26.6.3" + "@jest/types" "^26.6.2" + babel-jest "^26.6.3" + chalk "^4.0.0" deepmerge "^4.2.2" glob "^7.1.1" - jest-environment-jsdom "^25.4.0" - jest-environment-node "^25.4.0" - jest-get-type "^25.2.6" - jest-jasmine2 "^25.4.0" - jest-regex-util "^25.2.6" - jest-resolve "^25.4.0" - jest-util "^25.4.0" - jest-validate "^25.4.0" + graceful-fs "^4.2.4" + jest-environment-jsdom "^26.6.2" + jest-environment-node "^26.6.2" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.6.3" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" micromatch "^4.0.2" - pretty-format "^25.4.0" - realpath-native "^2.0.0" + pretty-format "^26.6.2" -jest-diff@^25.2.1, jest-diff@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-diff/-/jest-diff-25.4.0.tgz#260b70f19a46c283adcad7f081cae71eb784a634" - integrity sha512-kklLbJVXW0y8UKOWOdYhI6TH5MG6QAxrWiBMgQaPIuhj3dNFGirKCd+/xfplBXICQ7fI+3QcqHm9p9lWu1N6ug== +jest-diff@^26.0.0, jest-diff@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== dependencies: - chalk "^3.0.0" - diff-sequences "^25.2.6" - jest-get-type "^25.2.6" - pretty-format "^25.4.0" + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" -jest-docblock@^25.3.0: - version "25.3.0" - resolved "http://127.0.0.1:4873/jest-docblock/-/jest-docblock-25.3.0.tgz#8b777a27e3477cd77a168c05290c471a575623ef" - integrity sha512-aktF0kCar8+zxRHxQZwxMy70stc9R1mOmrLsT5VO3pIT0uzGRSDAXxSlz4NqQWpuLjPpuMhPRl7H+5FRsvIQAg== +jest-docblock@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== dependencies: detect-newline "^3.0.0" -jest-each@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-each/-/jest-each-25.4.0.tgz#ad4e46164764e8e77058f169a0076a7f86f6b7d4" - integrity sha512-lwRIJ8/vQU/6vq3nnSSUw1Y3nz5tkYSFIywGCZpUBd6WcRgpn8NmJoQICojbpZmsJOJNHm0BKdyuJ6Xdx+eDQQ== +jest-each@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" + integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== dependencies: - "@jest/types" "^25.4.0" - chalk "^3.0.0" - jest-get-type "^25.2.6" - jest-util "^25.4.0" - pretty-format "^25.4.0" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + jest-get-type "^26.3.0" + jest-util "^26.6.2" + pretty-format "^26.6.2" -jest-environment-jsdom@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-environment-jsdom/-/jest-environment-jsdom-25.4.0.tgz#bbfc7f85bb6ade99089062a830c79cb454565cf0" - integrity sha512-KTitVGMDrn2+pt7aZ8/yUTuS333w3pWt1Mf88vMntw7ZSBNDkRS6/4XLbFpWXYfWfp1FjcjQTOKzbK20oIehWQ== +jest-environment-jsdom@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" + integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== dependencies: - "@jest/environment" "^25.4.0" - "@jest/fake-timers" "^25.4.0" - "@jest/types" "^25.4.0" - jest-mock "^25.4.0" - jest-util "^25.4.0" - jsdom "^15.2.1" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + jsdom "^16.4.0" -jest-environment-node@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-environment-node/-/jest-environment-node-25.4.0.tgz#188aef01ae6418e001c03fdd1c299961e1439082" - integrity sha512-wryZ18vsxEAKFH7Z74zi/y/SyI1j6UkVZ6QsllBuT/bWlahNfQjLNwFsgh/5u7O957dYFoXj4yfma4n4X6kU9A== +jest-environment-node@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" + integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== dependencies: - "@jest/environment" "^25.4.0" - "@jest/fake-timers" "^25.4.0" - "@jest/types" "^25.4.0" - jest-mock "^25.4.0" - jest-util "^25.4.0" - semver "^6.3.0" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" -jest-get-type@^25.2.6: - version "25.2.6" - resolved "http://127.0.0.1:4873/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" - integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-haste-map@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-haste-map/-/jest-haste-map-25.4.0.tgz#da7c309dd7071e0a80c953ba10a0ec397efb1ae2" - integrity sha512-5EoCe1gXfGC7jmXbKzqxESrgRcaO3SzWXGCnvp9BcT0CFMyrB1Q6LIsjl9RmvmJGQgW297TCfrdgiy574Rl9HQ== +jest-haste-map@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== dependencies: - "@jest/types" "^25.4.0" + "@jest/types" "^26.6.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" - graceful-fs "^4.2.3" - jest-serializer "^25.2.6" - jest-util "^25.4.0" - jest-worker "^25.4.0" + graceful-fs "^4.2.4" + jest-regex-util "^26.0.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" micromatch "^4.0.2" sane "^4.0.3" walker "^1.0.7" - which "^2.0.2" optionalDependencies: fsevents "^2.1.2" -jest-jasmine2@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-jasmine2/-/jest-jasmine2-25.4.0.tgz#3d3d19514022e2326e836c2b66d68b4cb63c5861" - integrity sha512-QccxnozujVKYNEhMQ1vREiz859fPN/XklOzfQjm2j9IGytAkUbSwjFRBtQbHaNZ88cItMpw02JnHGsIdfdpwxQ== +jest-jasmine2@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== dependencies: "@babel/traverse" "^7.1.0" - "@jest/environment" "^25.4.0" - "@jest/source-map" "^25.2.6" - "@jest/test-result" "^25.4.0" - "@jest/types" "^25.4.0" - chalk "^3.0.0" + "@jest/environment" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" co "^4.6.0" - expect "^25.4.0" + expect "^26.6.2" is-generator-fn "^2.0.0" - jest-each "^25.4.0" - jest-matcher-utils "^25.4.0" - jest-message-util "^25.4.0" - jest-runtime "^25.4.0" - jest-snapshot "^25.4.0" - jest-util "^25.4.0" - pretty-format "^25.4.0" + jest-each "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + pretty-format "^26.6.2" throat "^5.0.0" -jest-leak-detector@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-leak-detector/-/jest-leak-detector-25.4.0.tgz#cf94a160c78e53d810e7b2f40b5fd7ee263375b3" - integrity sha512-7Y6Bqfv2xWsB+7w44dvZuLs5SQ//fzhETgOGG7Gq3TTGFdYvAgXGwV8z159RFZ6fXiCPm/szQ90CyfVos9JIFQ== +jest-leak-detector@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" + integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== dependencies: - jest-get-type "^25.2.6" - pretty-format "^25.4.0" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" -jest-matcher-utils@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-matcher-utils/-/jest-matcher-utils-25.4.0.tgz#dc3e7aec402a1e567ed80b572b9ad285878895e6" - integrity sha512-yPMdtj7YDgXhnGbc66bowk8AkQ0YwClbbwk3Kzhn5GVDrciiCr27U4NJRbrqXbTdtxjImONITg2LiRIw650k5A== +jest-matcher-utils@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== dependencies: - chalk "^3.0.0" - jest-diff "^25.4.0" - jest-get-type "^25.2.6" - pretty-format "^25.4.0" + chalk "^4.0.0" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" -jest-message-util@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-message-util/-/jest-message-util-25.4.0.tgz#2899e8bc43f5317acf8dfdfe89ea237d354fcdab" - integrity sha512-LYY9hRcVGgMeMwmdfh9tTjeux1OjZHMusq/E5f3tJN+dAoVVkJtq5ZUEPIcB7bpxDUt2zjUsrwg0EGgPQ+OhXQ== +jest-message-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== dependencies: "@babel/code-frame" "^7.0.0" - "@jest/types" "^25.4.0" - "@types/stack-utils" "^1.0.1" - chalk "^3.0.0" + "@jest/types" "^26.6.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" micromatch "^4.0.2" + pretty-format "^26.6.2" slash "^3.0.0" - stack-utils "^1.0.1" + stack-utils "^2.0.2" -jest-mock@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-mock/-/jest-mock-25.4.0.tgz#ded7d64b5328d81d78d2138c825d3a45e30ec8ca" - integrity sha512-MdazSfcYAUjJjuVTTnusLPzE0pE4VXpOUzWdj8sbM+q6abUjm3bATVPXFqTXrxSieR8ocpvQ9v/QaQCftioQFg== +jest-mock@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== dependencies: - "@jest/types" "^25.4.0" + "@jest/types" "^26.6.2" + "@types/node" "*" -jest-pnp-resolver@^1.2.1: - version "1.2.1" - resolved "http://127.0.0.1:4873/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" - integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== +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@^25.2.6: - version "25.2.6" - resolved "http://127.0.0.1:4873/jest-regex-util/-/jest-regex-util-25.2.6.tgz#d847d38ba15d2118d3b06390056028d0f2fd3964" - integrity sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw== +jest-regex-util@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-resolve-dependencies@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-resolve-dependencies/-/jest-resolve-dependencies-25.4.0.tgz#783937544cfc40afcc7c569aa54748c4b3f83f5a" - integrity sha512-A0eoZXx6kLiuG1Ui7wITQPl04HwjLErKIJTt8GR3c7UoDAtzW84JtCrgrJ6Tkw6c6MwHEyAaLk7dEPml5pf48A== +jest-resolve-dependencies@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" + integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== dependencies: - "@jest/types" "^25.4.0" - jest-regex-util "^25.2.6" - jest-snapshot "^25.4.0" + "@jest/types" "^26.6.2" + jest-regex-util "^26.0.0" + jest-snapshot "^26.6.2" -jest-resolve@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-resolve/-/jest-resolve-25.4.0.tgz#6f4540ce0d419c4c720e791e871da32ba4da7a60" - integrity sha512-wOsKqVDFWUiv8BtLMCC6uAJ/pHZkfFgoBTgPtmYlsprAjkxrr2U++ZnB3l5ykBMd2O24lXvf30SMAjJIW6k2aA== +jest-resolve@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== dependencies: - "@jest/types" "^25.4.0" - browser-resolve "^1.11.3" - chalk "^3.0.0" - jest-pnp-resolver "^1.2.1" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-pnp-resolver "^1.2.2" + jest-util "^26.6.2" read-pkg-up "^7.0.1" - realpath-native "^2.0.0" - resolve "^1.15.1" + resolve "^1.18.1" slash "^3.0.0" -jest-runner@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-runner/-/jest-runner-25.4.0.tgz#6ca4a3d52e692bbc081228fa68f750012f1f29e5" - integrity sha512-wWQSbVgj2e/1chFdMRKZdvlmA6p1IPujhpLT7TKNtCSl1B0PGBGvJjCaiBal/twaU2yfk8VKezHWexM8IliBfA== +jest-runner@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" + integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== dependencies: - "@jest/console" "^25.4.0" - "@jest/environment" "^25.4.0" - "@jest/test-result" "^25.4.0" - "@jest/types" "^25.4.0" - chalk "^3.0.0" + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.7.1" exit "^0.1.2" - graceful-fs "^4.2.3" - jest-config "^25.4.0" - jest-docblock "^25.3.0" - jest-haste-map "^25.4.0" - jest-jasmine2 "^25.4.0" - jest-leak-detector "^25.4.0" - jest-message-util "^25.4.0" - jest-resolve "^25.4.0" - jest-runtime "^25.4.0" - jest-util "^25.4.0" - jest-worker "^25.4.0" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-docblock "^26.0.0" + jest-haste-map "^26.6.2" + jest-leak-detector "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + jest-runtime "^26.6.3" + jest-util "^26.6.2" + jest-worker "^26.6.2" source-map-support "^0.5.6" throat "^5.0.0" -jest-runtime@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-runtime/-/jest-runtime-25.4.0.tgz#1e5227a9e2159d26ae27dcd426ca6bc041983439" - integrity sha512-lgNJlCDULtXu9FumnwCyWlOub8iytijwsPNa30BKrSNtgoT6NUMXOPrZvsH06U6v0wgD/Igwz13nKA2wEKU2VA== +jest-runtime@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== dependencies: - "@jest/console" "^25.4.0" - "@jest/environment" "^25.4.0" - "@jest/source-map" "^25.2.6" - "@jest/test-result" "^25.4.0" - "@jest/transform" "^25.4.0" - "@jest/types" "^25.4.0" + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/globals" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" "@types/yargs" "^15.0.0" - chalk "^3.0.0" + chalk "^4.0.0" + cjs-module-lexer "^0.6.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.3" - graceful-fs "^4.2.3" - jest-config "^25.4.0" - jest-haste-map "^25.4.0" - jest-message-util "^25.4.0" - jest-mock "^25.4.0" - jest-regex-util "^25.2.6" - jest-resolve "^25.4.0" - jest-snapshot "^25.4.0" - jest-util "^25.4.0" - jest-validate "^25.4.0" - realpath-native "^2.0.0" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" slash "^3.0.0" strip-bom "^4.0.0" - yargs "^15.3.1" + yargs "^15.4.1" -jest-serializer@^25.2.6: - version "25.2.6" - resolved "http://127.0.0.1:4873/jest-serializer/-/jest-serializer-25.2.6.tgz#3bb4cc14fe0d8358489dbbefbb8a4e708ce039b7" - integrity sha512-RMVCfZsezQS2Ww4kB5HJTMaMJ0asmC0BHlnobQC6yEtxiFKIxohFA4QSXSabKwSggaNkqxn6Z2VwdFCjhUWuiQ== +jest-serializer@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" -jest-snapshot@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-snapshot/-/jest-snapshot-25.4.0.tgz#e0b26375e2101413fd2ccb4278a5711b1922545c" - integrity sha512-J4CJ0X2SaGheYRZdLz9CRHn9jUknVmlks4UBeu270hPAvdsauFXOhx9SQP2JtRzhnR3cvro/9N9KP83/uvFfRg== +jest-snapshot@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== dependencies: "@babel/types" "^7.0.0" - "@jest/types" "^25.4.0" - "@types/prettier" "^1.19.0" - chalk "^3.0.0" - expect "^25.4.0" - jest-diff "^25.4.0" - jest-get-type "^25.2.6" - jest-matcher-utils "^25.4.0" - jest-message-util "^25.4.0" - jest-resolve "^25.4.0" - make-dir "^3.0.0" + "@jest/types" "^26.6.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.0.0" + chalk "^4.0.0" + expect "^26.6.2" + graceful-fs "^4.2.4" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" natural-compare "^1.4.0" - pretty-format "^25.4.0" - semver "^6.3.0" + pretty-format "^26.6.2" + semver "^7.3.2" -jest-util@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-util/-/jest-util-25.4.0.tgz#6a093d09d86d2b41ef583e5fe7dd3976346e1acd" - integrity sha512-WSZD59sBtAUjLv1hMeKbNZXmMcrLRWcYqpO8Dz8b4CeCTZpfNQw2q9uwrYAD+BbJoLJlu4ezVPwtAmM/9/SlZA== +jest-util@^26.1.0, jest-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== dependencies: - "@jest/types" "^25.4.0" - chalk "^3.0.0" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" is-ci "^2.0.0" - make-dir "^3.0.0" + micromatch "^4.0.2" -jest-validate@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-validate/-/jest-validate-25.4.0.tgz#2e177a93b716a137110eaf2768f3d9095abd3f38" - integrity sha512-hvjmes/EFVJSoeP1yOl8qR8mAtMR3ToBkZeXrD/ZS9VxRyWDqQ/E1C5ucMTeSmEOGLipvdlyipiGbHJ+R1MQ0g== +jest-validate@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== dependencies: - "@jest/types" "^25.4.0" - camelcase "^5.3.1" - chalk "^3.0.0" - jest-get-type "^25.2.6" + "@jest/types" "^26.6.2" + camelcase "^6.0.0" + chalk "^4.0.0" + jest-get-type "^26.3.0" leven "^3.1.0" - pretty-format "^25.4.0" + pretty-format "^26.6.2" -jest-watcher@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-watcher/-/jest-watcher-25.4.0.tgz#63ec0cd5c83bb9c9d1ac95be7558dd61c995ff05" - integrity sha512-36IUfOSRELsKLB7k25j/wutx0aVuHFN6wO94gPNjQtQqFPa2rkOymmx9rM5EzbF3XBZZ2oqD9xbRVoYa2w86gw== +jest-watcher@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" + integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== dependencies: - "@jest/test-result" "^25.4.0" - "@jest/types" "^25.4.0" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" ansi-escapes "^4.2.1" - chalk "^3.0.0" - jest-util "^25.4.0" - string-length "^3.1.0" + chalk "^4.0.0" + jest-util "^26.6.2" + string-length "^4.0.1" -jest-worker@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest-worker/-/jest-worker-25.4.0.tgz#ee0e2ceee5a36ecddf5172d6d7e0ab00df157384" - integrity sha512-ghAs/1FtfYpMmYQ0AHqxV62XPvKdUDIBBApMZfly+E9JEmYh2K45G0R5dWxx986RN12pRCxsViwQVtGl+N4whw== +jest-worker@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== dependencies: + "@types/node" "*" merge-stream "^2.0.0" supports-color "^7.0.0" -jest@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/jest/-/jest-25.4.0.tgz#fb96892c5c4e4a6b9bcb12068849cddf4c5f8cc7" - integrity sha512-XWipOheGB4wai5JfCYXd6vwsWNwM/dirjRoZgAa7H2wd8ODWbli2AiKjqG8AYhyx+8+5FBEdpO92VhGlBydzbw== +jest@^26.1.0: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" + integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== dependencies: - "@jest/core" "^25.4.0" + "@jest/core" "^26.6.3" import-local "^3.0.2" - jest-cli "^25.4.0" + jest-cli "^26.6.3" js-beautify@^1.6.14: - version "1.11.0" - resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.11.0.tgz#afb873dc47d58986360093dcb69951e8bcd5ded2" - integrity sha512-a26B+Cx7USQGSWnz9YxgJNMmML/QG2nqIaL7VVYPCXbqiKz8PN0waSNvroMtvAK6tY7g/wPdNWGEP+JTNIBr6A== + version "1.13.4" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.13.4.tgz#1cad80b9e89cfc455b3a14f0eaf4dc10b6ae1206" + integrity sha512-M5yEWwonlEO3kPcCZ3K3KBSpFRZAEO3FAWC6wtbIGeyg7dusStxvF0WG+HRLBoMZqREXSRSxkkqClDE865x1sg== dependencies: config-chain "^1.1.12" editorconfig "^0.15.3" glob "^7.1.3" - mkdirp "~1.0.3" - nopt "^4.0.3" + mkdirp "^1.0.4" + nopt "^5.0.0" -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.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.13.1" - resolved "http://127.0.0.1:4873/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + 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" +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" + integrity sha1-sBMHyym2GKHtJux56RH4A8TaAEA= + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jsdom@^15.2.1: - version "15.2.1" - resolved "http://127.0.0.1:4873/jsdom/-/jsdom-15.2.1.tgz#d2feb1aef7183f86be521b8c6833ff5296d07ec5" - integrity sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g== +jsdom@^16.4.0: + version "16.4.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb" + integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w== dependencies: - abab "^2.0.0" - acorn "^7.1.0" - acorn-globals "^4.3.2" - array-equal "^1.0.0" - cssom "^0.4.1" - cssstyle "^2.0.0" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.1" - html-encoding-sniffer "^1.0.2" + abab "^2.0.3" + acorn "^7.1.1" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.2.0" + data-urls "^2.0.0" + decimal.js "^10.2.0" + domexception "^2.0.1" + escodegen "^1.14.1" + html-encoding-sniffer "^2.0.1" + is-potential-custom-element-name "^1.0.0" nwsapi "^2.2.0" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.7" - saxes "^3.1.9" - symbol-tree "^3.2.2" + parse5 "5.1.1" + request "^2.88.2" + request-promise-native "^1.0.8" + saxes "^5.0.0" + symbol-tree "^3.2.4" tough-cookie "^3.0.1" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" + 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 "^7.0.0" - ws "^7.0.0" + whatwg-url "^8.0.0" + ws "^7.2.3" xml-name-validator "^3.0.0" jsesc@^2.5.1: version "2.5.2" - resolved "http://127.0.0.1:4873/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + json-parse-better-errors@^1.0.1: version "1.0.2" - resolved "http://127.0.0.1:4873/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +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= + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -2961,56 +4112,81 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -juice@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/juice/-/juice-5.2.0.tgz#a40ea144bde2845fe2aade46a81f493f8ea677a0" - integrity sha512-0l6GZmT3efexyaaay3SchKT5kG311N59TEFP5lfvEy0nz9SNqjx311plJ3b4jze7arsmDsiHQLh/xnAuk0HFTQ== +juice@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/juice/-/juice-7.0.0.tgz#509bed6adbb6e4bbaa7fbfadac4e2e83e8c89ba3" + integrity sha512-AjKQX31KKN+uJs+zaf+GW8mBO/f/0NqSh2moTMyvwBY+4/lXIYTU8D8I2h6BAV3Xnz6GGsbalUyFqbYMe+Vh+Q== dependencies: - cheerio "^0.22.0" - commander "^2.15.1" - cross-spawn "^6.0.5" - deep-extend "^0.6.0" - mensch "^0.3.3" + cheerio "^1.0.0-rc.3" + commander "^5.1.0" + mensch "^0.3.4" slick "^1.12.2" - web-resource-inliner "^4.3.1" + web-resource-inliner "^5.0.0" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" - resolved "http://127.0.0.1:4873/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" - resolved "http://127.0.0.1:4873/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" - resolved "http://127.0.0.1:4873/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" - resolved "http://127.0.0.1:4873/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== kleur@^3.0.3: version "3.0.3" - resolved "http://127.0.0.1:4873/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +latest-version@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +lazy@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" + integrity sha1-2qBoIGKCVCwIgojpdcKXwa53tpA= + leven@^3.1.0: version "3.1.0" - resolved "http://127.0.0.1:4873/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + levn@~0.3.0: version "0.3.0" - resolved "http://127.0.0.1:4873/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" @@ -3018,7 +4194,7 @@ levn@~0.3.0: lines-and-columns@^1.1.6: version "1.1.6" - resolved "http://127.0.0.1:4873/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= locate-path@^3.0.0: @@ -3031,110 +4207,41 @@ locate-path@^3.0.0: locate-path@^5.0.0: version "5.0.0" - resolved "http://127.0.0.1:4873/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + 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.assignin@^4.0.9: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" - integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= - -lodash.bind@^4.1.4: - version "4.2.1" - resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" - integrity sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU= - -lodash.defaults@^4.0.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= - -lodash.filter@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" - integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4= - -lodash.flatten@^4.2.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.foreach@^4.3.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" - integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= - -lodash.map@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" - integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= - lodash.memoize@4.x: version "4.1.2" - resolved "http://127.0.0.1:4873/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= -lodash.merge@^4.4.0: - 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.pick@^4.2.1: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" - integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= - -lodash.reduce@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" - integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= - -lodash.reject@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" - integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU= - -lodash.some@^4.4.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" - integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= - lodash.sortby@^4.7.0: version "4.7.0" - resolved "http://127.0.0.1:4873/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash.unescape@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" - integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= - -lodash@^4.17.13, lodash@^4.17.15: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -lolex@^5.0.0: - version "5.1.2" - resolved "http://127.0.0.1:4873/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" - integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== - dependencies: - "@sinonjs/commons" "^1.7.0" - -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" +lodash@^4.15.0, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== lower-case@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + lru-cache@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" @@ -3143,33 +4250,67 @@ lru-cache@^4.1.5: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +maildev@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/maildev/-/maildev-1.1.0.tgz#8b6977f244373be00112c942ae15dd32f5c225c9" + integrity sha512-D7mrEM/i4c5AX72aRBN9mO5snsGhEs7MvNFWmrSsRL94sIH0/zVQ1GE+ysN9J7lFMLkXNy2xPG3SGP2cjPrCRw== + dependencies: + async "^3.1.0" + commander "^2.20.0" + cors "^2.8.5" + express "^4.17.1" + mailparser-mit "^1.0.0" + opn "^6.0.0" + rimraf "^2.6.3" + smtp-connection "4.0.2" + smtp-server "3.5.0" + socket.io "2.2.0" + wildstring "1.0.9" + +mailparser-mit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mailparser-mit/-/mailparser-mit-1.0.0.tgz#19df8436c2a02e1d34a03ec518a2eb065e0a94a4" + integrity sha512-sckRITNb3VCT1sQ275g47MAN786pQ5lU20bLY5f794dF/ARGzuVATQ64gO13FOw8jayjFT10e5ttsripKGGXcw== + dependencies: + addressparser "^1.0.1" + iconv-lite "~0.4.24" + mime "^1.6.0" + uue "^3.1.0" + make-dir@^3.0.0: version "3.1.0" - resolved "http://127.0.0.1:4873/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + 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.x, make-error@^1.1.1: version "1.3.6" - resolved "http://127.0.0.1:4873/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== makeerror@1.0.x: version "1.0.11" - resolved "http://127.0.0.1:4873/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= dependencies: tmpl "1.0.x" map-cache@^0.2.2: version "0.2.2" - resolved "http://127.0.0.1:4873/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= map-visit@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" @@ -3179,7 +4320,7 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -mensch@^0.3.3: +mensch@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/mensch/-/mensch-0.3.4.tgz#770f91b46cb16ea5b204ee735768c3f0c491fecd" integrity sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g== @@ -3191,25 +4332,22 @@ merge-descriptors@1.0.1: merge-stream@^2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -methods@~1.1.2: +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@4.x, micromatch@^4.0.2: - version "4.0.2" - resolved "http://127.0.0.1:4873/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - micromatch@^3.1.4: version "3.1.10" - resolved "http://127.0.0.1:4873/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" @@ -3226,33 +4364,46 @@ micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -mime-db@1.43.0: - version "1.43.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" - integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + +mime-db@1.45.0, "mime-db@>= 1.43.0 < 2": + version "1.45.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea" + integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w== mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.26" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" - integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== + version "2.1.28" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd" + integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ== dependencies: - mime-db "1.43.0" + mime-db "1.45.0" -mime@1.6.0: +mime@1.6.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== -mimer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mimer/-/mimer-1.0.0.tgz#32251bef4dc7a63184db3a1082ed9be3abe0f3db" - integrity sha512-4ZJvCzfcwsBgPbkKXUzGoVZMWjv8IDIygkGzVc7uUYhgnK0t2LmGxxjdgH1i+pn0/KQfB5F/VKUJlfyTSOFQjg== +mime@^2.4.6: + version "2.5.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.0.tgz#2b4af934401779806ee98026bb42e8c1ae1876b1" + integrity sha512-ft3WayFSFUVBuJj7BMLKAQcSlItKtfjsKDDsii3rqFDAZ7t11zRe8ASw/GlmivGwVUYtwkQrxiGGpL6gFvB0ag== mimic-fn@^2.1.0: version "2.1.0" - resolved "http://127.0.0.1:4873/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -3265,364 +4416,365 @@ minimist@^1.1.1, 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== +minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + mixin-deep@^1.2.0: version "1.3.2" - resolved "http://127.0.0.1:4873/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" -mjml-accordion@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-accordion/-/mjml-accordion-4.6.2.tgz#f034155f181c2887b8f0f6bdd0d4c861bed981e2" - integrity sha512-ex5kU3me1ggBw4jMzNce+gEA13DClkq5lTUd7Aec+9obHh0X9/hQJ/RT0kVDn5i1ZPMcMmI94Y8CliMBk9MIKg== +mjml-accordion@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-accordion/-/mjml-accordion-4.8.1.tgz#8917b263336acca062665d9f37eb9fb2b77eaf3e" + integrity sha512-VviMSaWlHkiTt0bVSdaIeDQjkApAjJR2whEhVvQmEjpu5gJdUS2Po6dQHrd/0ub8gCVMzVq62UKJdPM0fTBlMw== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-body@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-body/-/mjml-body-4.6.2.tgz#42dc98e0ca0d62e06885cfb09a7f51e91c0a6af0" - integrity sha512-6+ULwmSmEoqelTTHPgjbZ0LaoDChsDijolzoT5wy+QHcwkBGmEpB0/6yI8YWNvpUlfkrSOOkzWbjdHQFWoiJng== +mjml-body@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-body/-/mjml-body-4.8.1.tgz#6bca36a037410f8c11cd23e4b210bbbd424c59b2" + integrity sha512-L8DjOveb1GsxSAOye7CyeTsqBQ13DBQCuRVz9dXF1pjycawgK3eBvMHhlXAkCcuNlRUuH0/jI04f2whkYTYOZg== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-button@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-button/-/mjml-button-4.6.2.tgz#cfb944b4d5d81302f0ce8984a33275804d16ac04" - integrity sha512-jHQCuQqUyZ6bLpWcdqbGwNIelpAVMBrtkXlToYCqG6PSF4uj3CfPnqV621PHyOex3BV2qgKklzTuGICMHC5D8g== +mjml-button@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-button/-/mjml-button-4.8.1.tgz#c0677d128e28acf74b65a34237a12248442cf48f" + integrity sha512-qiPtRQkC1/4QjHPTA8NvpVgK8jRIevEo2pgxw8gDsstkWSnV/TxrzQxQ6iWaWI7gGD3ZOQUMvVTpUeuPAJGssw== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-carousel@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-carousel/-/mjml-carousel-4.6.2.tgz#778745f9d4f315744d37c70460caa620ee485c6e" - integrity sha512-w1L71B2mmFlPGK6OgGbZP6qRtg7NMH4cp/VFwww8PpAStN9tXRf2exMyEBdoitrmpMGWbgmkLQrQ49w9OYPBVw== +mjml-carousel@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-carousel/-/mjml-carousel-4.8.1.tgz#ecad8db5c3a251978fb2d9ec92f15e4acae1e8a5" + integrity sha512-YlYy6sQuhi1Q889WW9OwQp9qZvb0mR7M/9rnCgRzI5SFd9dICwafEz5hKHTfy4o/d1CWnKF5Gp/ovg/Ci6pm4A== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-cli@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-cli/-/mjml-cli-4.6.2.tgz#14a246ed37119dfc7268424f97b59768d94bacd5" - integrity sha512-Rxbv9YflBgaSU21dS95k8ar85VcCsK37LclIqupD13TMHbFNobIO/DVcK5+P/R5VZIblqK7HmTh1FQU4uGEplQ== +mjml-cli@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-cli/-/mjml-cli-4.8.1.tgz#04ef02f7cbec9de1744d69a856319d70b071607d" + integrity sha512-Yb/Ykwin4XLpX9uonFW1GK7aMc3CBUDtcbPsVMC/p9g3U1rXi/Bp4MFpya8WoHT9D4N97gGJPEQ7ndCrzMrgNQ== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" chokidar "^3.0.0" glob "^7.1.1" - lodash "^4.17.15" - mjml-core "4.6.2" - mjml-migrate "4.6.0" - mjml-parser-xml "4.6.2" - mjml-validator "4.5.0" - yargs "^13.3.0" - -mjml-column@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-column/-/mjml-column-4.6.2.tgz#d652a0d9fbbfc1a6257ed8ade9e8672cd711c54e" - integrity sha512-5OHqUOQoJPx73VctXiDjDysuuIwDys1Rd8ezcGSawkwepYcY7afXa23mBgV/QkOfJmeowLBoLwcuy4TsWWHmbg== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-core@4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/mjml-core/-/mjml-core-4.5.0.tgz#09b243b53d4eecf8e186d1f1acda0f1f417870a6" - integrity sha512-/9M4Dt0f7zaVzP7OJZlqaVWS1ijkoEoF6dKKeiXqRQ3oTvyiTEATHGA5xeifsU4dOzDFhdfFbu54LJOmHdPlVw== - dependencies: - babel-runtime "^6.26.0" - html-minifier "^3.5.3" - js-beautify "^1.6.14" - juice "^5.2.0" - lodash "^4.17.15" - mjml-migrate "4.5.0" - mjml-parser-xml "4.5.0" - mjml-validator "4.5.0" - -mjml-core@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-core/-/mjml-core-4.6.2.tgz#dfae3754a90a7e11e2b03dfb18920ca6824dbd49" - integrity sha512-Rk5J+IRUgbtJ+acWWY/N1qqS+0qtQY5Vb+KwoOWPtGh2iHB01vNF02/qVEEocaaRHARP556kfO1RLSgsRH/iew== - dependencies: - babel-runtime "^6.26.0" - html-minifier "^3.5.3" - js-beautify "^1.6.14" - juice "^5.2.0" - lodash "^4.17.15" - mjml-migrate "4.6.0" - mjml-parser-xml "4.6.2" - mjml-validator "4.5.0" - -mjml-divider@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-divider/-/mjml-divider-4.6.2.tgz#b0fa8b6e6a17e40176c7962bac4ab9306fb26745" - integrity sha512-dcMUk361US2s/XA7UuTDKrSSdGP46b4GVfKf0/9H3r78gSgDBph0r1g89ar7Dd4n+qvdTOL7O71dlmAlI/X7Dg== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-group@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-group/-/mjml-group-4.6.2.tgz#e44f4045e543064e07ccc179435b95809842fa6a" - integrity sha512-5c+MWKmeeTCKvPfrALHwOUVBedC6NwgAS7jCQeKZ1gJsS9bzdZRlkiYKd7XNLTrOT97XoAJ4DAP9B4x3OrXtBw== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-head-attributes@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-head-attributes/-/mjml-head-attributes-4.6.2.tgz#1d4b6c1fc44507e2a5b330c587918748b2b20127" - integrity sha512-4r5exX6smeltj3Is6kd1lTxwqECAIFjQY7kkGhJeutbehmXM49iw84IbMnvYJ3FUwYx7efGdOwPFPTeM677RsA== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-head-breakpoint@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-head-breakpoint/-/mjml-head-breakpoint-4.6.2.tgz#e23c5a80a07464a4df35dd5ea788120fbbb0c432" - integrity sha512-uzBqfjoLaHBi7QKUwmskydBdICSNoFKsft5aFTua1yFxCfwRd5LC8LUenlll24pJjnajPVxNuSLf2U7AWMyCSQ== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-head-font@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-head-font/-/mjml-head-font-4.6.2.tgz#b7d57d126c5ba50f3cbc92dd5accf012d6db7f55" - integrity sha512-degQDrYY9sNjRlnNqJOkmiH2ZJ9nw05G9TXO08KMCfx6FS2sH4ry1eB3D+RZOIdhP/S5maqZ16KMVqkt+kEJjw== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-head-preview@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-head-preview/-/mjml-head-preview-4.6.2.tgz#30e13c8936f7869bf17d16a729b7fefa74955864" - integrity sha512-IXKJpUnYnpUpKlKz7VAWEmufiAU/dTv2s99Ns26mIFjY3aveTr+TysvUjjofQmk6+29Z8Zx63bGaGurwr9ykvA== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-head-style@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-head-style/-/mjml-head-style-4.6.2.tgz#7ece2cd1db121b319e38c76218a40e99cafe4089" - integrity sha512-ZJuUcKUeklDrA1hhG0dAmB3ph1E9js3l0uWuMuWluZiA9ix29wsxsOu119oElyKEpYstd84cwmcuf66X3IyhTg== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-head-title@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-head-title/-/mjml-head-title-4.6.2.tgz#a2237ea5da1a052c62b30d2babb7eb4ef154e3cf" - integrity sha512-VjZKlt4GGNGozFlM+BQKGbbPq50COH+TOU2Hgdwm9w6XQyKBcxFcILWa9gEd2slKuDpvetN7ri2QHPii7n2yZg== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-head@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-head/-/mjml-head-4.6.2.tgz#ffc154da50ad4808ae26c881dc7933442d5ff8bd" - integrity sha512-UEa5OQEGJdqYThSTAbE+LJuinTnOMMrnJqm+dxb0ft7D50Bi7UH4y3Xs//SQQELz8ntlOQq2C/7g6BZ4yRNxhg== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-hero@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-hero/-/mjml-hero-4.6.2.tgz#fe92ed1018c629749c39235103a48c0452c30391" - integrity sha512-7IdSSOBQzC6apZwKNLr83k01kBRpTfZZ2oryVlye2E7kGLV+knONglOicWm8qfs/mBBP+FKoZDrOekyD3Lz5Yg== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-image@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-image/-/mjml-image-4.6.2.tgz#1a9abc55165418e12703dddcedd3f2434e59e4e4" - integrity sha512-g2vtdy15K5BLd30Wf73FgTnjOdvVsR+DDHbJt5MRTBYeeZFAj/2Y1HSoCalYDGkee39a86j5JGlb2qnUjGVIpw== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - -mjml-migrate@4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/mjml-migrate/-/mjml-migrate-4.5.0.tgz#fa9b6dae1de00544448106bee50c9485c40e7749" - integrity sha512-zzAKSrGpF+OVoa3GHVS7O2A4WZPLBV/Nrc80MGaLS4hhBbuj2WeUdaugVlIMXRRuhQ+nP+k0fZSM8tonDDjd2w== - dependencies: - babel-runtime "^6.26.0" - commander "^2.11.0" + html-minifier "^4.0.0" js-beautify "^1.6.14" lodash "^4.17.15" - mjml-core "4.5.0" - mjml-parser-xml "4.5.0" + mjml-core "4.8.1" + mjml-migrate "4.8.1" + mjml-parser-xml "4.8.1" + mjml-validator "4.8.1" + yargs "^16.1.0" -mjml-migrate@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/mjml-migrate/-/mjml-migrate-4.6.0.tgz#95a23dc3db2ff1f8a836685bf7f664ddd3ab095c" - integrity sha512-2aVe/NgT5TbXG3Sqbnw1uvtztB1opVGmmPeDs9cKbOxmncspRehWdW7EUREa491RmFvC/8krcXum+wbV0IHkjw== +mjml-column@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-column/-/mjml-column-4.8.1.tgz#f6b0a65a9b611c6f6feddfd88d3dd5453c1be42c" + integrity sha512-8UlYNtBgcEylnFAA+il+LEeuP8sf91ml7v9yV9GWVZpdS9o2eQI1LHtmlEZ6+PDVG9CYpmTm1XZ0YWqBsVVtBg== dependencies: - babel-runtime "^6.26.0" - commander "^2.11.0" + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-core@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-core/-/mjml-core-4.8.1.tgz#96dd54760411423fb579816da68adfa97530f66f" + integrity sha512-CXKzgu3BjgtSfNKDeihK75fLOhhimEZK4eU5ZCgVgtD5S3txfyA+IbRPKikcj5V/vF1Zxfipr3P4SMnVAIi1vA== + dependencies: + "@babel/runtime" "^7.8.7" + cheerio "1.0.0-rc.3" + detect-node "2.0.4" + html-minifier "^4.0.0" + js-beautify "^1.6.14" + juice "^7.0.0" + lodash "^4.17.15" + mjml-migrate "4.8.1" + mjml-parser-xml "4.8.1" + mjml-validator "4.8.1" + +mjml-divider@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-divider/-/mjml-divider-4.8.1.tgz#ca352e9de33cd9aba6fef76b791dcd75caa5ef33" + integrity sha512-kaDHd++6qfOp79dm9k/3o4uMLvhSMy01HjWO5+HCYGv9V4ZLHRHmz8MJVz9plpRByRsOV0gw88vXDNiGVqX6Eg== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-group@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-group/-/mjml-group-4.8.1.tgz#949c1f8580c1edf86dd33d5773c54799c0bb876a" + integrity sha512-839DbzEg9GzXgwjXSJZFcx3k18DiklAHCnhpy/fbH5C1IbFU0W5I3V105p2a9jeXVIvrRiDw4pCjoPSJsNu5lQ== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-head-attributes@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-head-attributes/-/mjml-head-attributes-4.8.1.tgz#ba64ec9183e578c3758a4fbcc3e10563a9a819f2" + integrity sha512-PthSJB+znbNfOZ5DHFiuoY9hG97rgmcKzq0Htn6YQuzVFEtvrKXf7cj57M23RkFq2Gcyvn/8VJ98F6kG1Pfq7A== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-head-breakpoint@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-head-breakpoint/-/mjml-head-breakpoint-4.8.1.tgz#4f3ccf56e7ae3469bc47ace220cc0ac255802abb" + integrity sha512-ABL6L5GKRE3wWY5YOZEHDp5MQN1oV9srTR13Ohe/IC3MHaLv78T98E8iEBYr51RnVlfMkhfGNJF8vn6C8EXIFQ== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-head-font@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-head-font/-/mjml-head-font-4.8.1.tgz#ca326e2d73054bc837add59cbf07eca42cfaecbb" + integrity sha512-Gm4QOKQOE87D6pCor1IqBT76PPd0fhtSXWpceacf9oS8QtZtI1VjNuP7TiEk+T5DZo5mM+0zKuhrW7EUPfku3w== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-head-html-attributes@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-head-html-attributes/-/mjml-head-html-attributes-4.8.1.tgz#28bee85179554c0d93de47e5ab7b604da592514f" + integrity sha512-WNZnF0+2Q3aBAYXvthiOHg4URPxUKdTSNmCsrTajqDrP/1A0lin5uLrKc/BGf2MiiBtSvz2kUYbkEBPn7qvSBA== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-head-preview@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-head-preview/-/mjml-head-preview-4.8.1.tgz#0757a5ba4ef91a72b0e1b4c093fe356539d49d98" + integrity sha512-7u9Y7p9DpmGedKMAzvRPl5u3vazi7AWj1iNV/cHyt6couWlszrLGiG2L9dxr58zSfsxvAyGLH+dVcx/qRsQwZA== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-head-style@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-head-style/-/mjml-head-style-4.8.1.tgz#e0e4c74b2df54d45343a4474fffaf481786e82f4" + integrity sha512-QeYHhSPzv3fV5vM1huFiERmLZ/UzJAxqSz/BJiqwZ0qawWLxVG6ku8VTwNQdiWKD4Wnsiijre41rwPttv4OiJQ== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-head-title@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-head-title/-/mjml-head-title-4.8.1.tgz#ee9c5035d1fcc2663e569b349e1ca05543b1b4a3" + integrity sha512-Nc49MlGxML4orDL9XKMnaZDHFSivGZnOTls/TH4nkZG+TLMzLf/6+f//Im1x8XiLKhWgETuGff7eFc1PadxVKg== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-head@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-head/-/mjml-head-4.8.1.tgz#d2e24096ca49f450937f7ccf4b33a3dc9e61c53a" + integrity sha512-6UeXCXFN/+8ehwE20weE68Kx1kaWySdffqPm2zjvDdOWQPEAO9tx3FnJk3MuR0kZ6vcvuM0KXYLXlC5rJS02Dg== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-hero@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-hero/-/mjml-hero-4.8.1.tgz#8524d9c66541afa506c645d1f3614cf801e5c408" + integrity sha512-LYe1mzNySN0M/ZHx8IMB5+v5MzKVHElujzywEFKnAFycWXPjRTvFUDp+PzWP55rbg5GILu4+pgD8ePZH02DHOQ== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-image@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-image/-/mjml-image-4.8.1.tgz#11884e8358764a06261c16605f8d5b2ea09c538f" + integrity sha512-3xHmUhdfoOVFzXkFV0bpq84ZGQgQrJbCVeArpz7DdwjjaEER7cYoleAMPtlgOlEyx1TwAJzClpIRO887MkV/qg== + dependencies: + "@babel/runtime" "^7.8.7" + lodash "^4.17.15" + mjml-core "4.8.1" + +mjml-migrate@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-migrate/-/mjml-migrate-4.8.1.tgz#e74f42e5b7baaa475ce1e784cc90e535f45309d0" + integrity sha512-U8s9uzgjsOt9so+oqq9Dd9x/bZfkPva8euzF2RiN09wfUIKfglMblZyarsbaVTyFT3BOFKbJ091YcVBobsCJiQ== + dependencies: + "@babel/runtime" "^7.8.7" js-beautify "^1.6.14" lodash "^4.17.15" - mjml-core "4.5.0" - mjml-parser-xml "4.5.0" + mjml-core "4.8.1" + mjml-parser-xml "4.8.1" + yargs "^16.1.0" -mjml-navbar@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-navbar/-/mjml-navbar-4.6.2.tgz#d1631a1031e132f4142b6d346246ecd0eb72b39d" - integrity sha512-9PWzcgytAd2GWSkZX7F7RZKQ5aS0QHIiOMtMSNGJbj/d8Xksqn0S+5vN0uBWqYv231SunQBjvBCClGHceqMW1w== +mjml-navbar@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-navbar/-/mjml-navbar-4.8.1.tgz#365f2b55980e9b247a67646b85922c6a29566ebd" + integrity sha512-6Y3ITpDYz9HytT69A59hk50/y1r7iOkGQL7PP2qltWAjj2eHxUpu0dsPfPvV0a2X6HB9DXOSPJSWdHNHowI/dQ== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-parser-xml@4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/mjml-parser-xml/-/mjml-parser-xml-4.5.0.tgz#85d4ea124518177596393dedb321519d746565a4" - integrity sha512-9NK9TnkDSJ0M7lMv1vuGjZumi1rqdv4Iwr9rBDpBPUvfv9ay7MoJrQjK28cu6PKcamOK6CHAFXihlV9Q6fbYaA== +mjml-parser-xml@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-parser-xml/-/mjml-parser-xml-4.8.1.tgz#0eddf3d6c070e01ba73e366865b9f3ff6f8ff016" + integrity sha512-kU9IpBVWfeDad/vuDpBt0okz9yRyvy+H6JRZqrUm+qDkzNQHEChnLl3U47FYj81SMuh0CVTGatCIi05pFC396g== dependencies: - babel-runtime "^6.26.0" - htmlparser2 "^3.9.2" + "@babel/runtime" "^7.8.7" + detect-node "2.0.4" + htmlparser2 "^4.1.0" lodash "^4.17.15" -mjml-parser-xml@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-parser-xml/-/mjml-parser-xml-4.6.2.tgz#071eb9512273e37a5b6d08b8f33915ad5570fe6d" - integrity sha512-d9QO/8szZE27xy+BwMHyjs4vIzRG6sQ/O/7PXsSfGgred3cDuk7PMwuC7rZefft6Un4vogk3/M+KR6KGVaEnbg== +mjml-raw@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-raw/-/mjml-raw-4.8.1.tgz#c2c1ac30677bce3ed57f63138194ff2dc7a37921" + integrity sha512-NIwHVcFDCOuFHB9dY1fLyRSRTuq//FcYPyorJrEt9TTEY16KznjRyJvJohPbF7bcLoYiqBUDFSRtI7qJFTFapg== dependencies: - babel-runtime "^6.26.0" - htmlparser2 "^3.9.2" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" + mjml-core "4.8.1" -mjml-raw@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-raw/-/mjml-raw-4.6.2.tgz#4142422e8d98976712c492f97c8e4939053f0a32" - integrity sha512-u/+Ql1iBWF0D4XSgasJoRzmV5g5UlP7cjUnPeslRjtFnZXWGQdRw8BFBCmvXkjAokSk22sQ+GgHEjP9ebshtdg== +mjml-section@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-section/-/mjml-section-4.8.1.tgz#f8341cbd8acceee609234b2fea619207cccb48f1" + integrity sha512-cksu5rVBioDjNZyyWBwV2oW+HdUGrESMQSACrJCgeQFTbkJ7GdiCqsGOGTZN4OoM8DvHAizXzOXHZY9GPC4M8g== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-section@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-section/-/mjml-section-4.6.2.tgz#81d7a316630f937791a67ff0497f67121c1916e3" - integrity sha512-bhKPdYq3vo8aaXwZ9HkG8CG4ss0vPFTGJ/kFkqnnvYIuxLJjILSBb4UoktvN0xCp15vXvEjHS0eJv4rZiAjzFQ== +mjml-social@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-social/-/mjml-social-4.8.1.tgz#ffb72c2db75a346b43267df87bca29192054623c" + integrity sha512-YU0eJg0BnqfV1JzHONWabnZ8c1xJATezVXe1z0xMhXpe/lPPWRjqv97Sf06h2NoK8z9F6PvifHBVv6/kU0HU6g== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-social@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-social/-/mjml-social-4.6.2.tgz#85575d67398a7de3e8287fc3037de835c8d49b2a" - integrity sha512-m++Ml0uWUby//i2hGz7FAfEamdx3PjPKGBOslHzKCY2Lpf2kvnDNNGzG/apKjUBtWRvlMHkkiCL2uJ05rvWdYg== +mjml-spacer@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-spacer/-/mjml-spacer-4.8.1.tgz#be24302a29fb2083bfd74ab31d00ec08e142920e" + integrity sha512-pMvL2YK0Phb7m78cwipWb+OmvP1TT1spsYDtC1qFuK46vkdOpesGS9dhPMG5iApbaKOcdmoIENtsD01agIzjjw== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-spacer@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-spacer/-/mjml-spacer-4.6.2.tgz#309756d65c1ac78b79eec04b45dd369588d4ddc1" - integrity sha512-U8tQY2Hwtbuw7wuLiYxNSwX7cH0olqVKolFdLMJZJf+TD2shbq/4XaPj6JXiBu6+OVeIsePPJtTVmh46oE0Kqg== +mjml-table@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-table/-/mjml-table-4.8.1.tgz#a50479e51aeb28d31492b57924ad355a3e746525" + integrity sha512-aXOThuC9d3wcnuigefqPcUTticSKul9+ElFKDiX5SEGmXbr3g5Mp3TaM9218GaXfyGJNFEe4eWfiwqjeRv8Fmw== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-table@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-table/-/mjml-table-4.6.2.tgz#e4cc1d846fa6eee1a1689412f8d26bb7b820bb9a" - integrity sha512-ZIG48ZRke30G9fd++YmC2NZuSohs2//STb6ozRIjp8ZcNGu8TVM837zUDnoSe5/iJ7O1kqMgwDx3oe5s4OOjdA== +mjml-text@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-text/-/mjml-text-4.8.1.tgz#01dd3579f1fa5c3a1379d5965ee61450af0c8ad5" + integrity sha512-wA+/pMEmJqDnSR45w6jon/f2HGnLddcc19DNo77EfW8yw6KVyjvDdRs5y6L0S7Ri265AsgzvG7hNbJ31AwjtJw== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - mjml-core "4.6.2" + mjml-core "4.8.1" -mjml-text@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-text/-/mjml-text-4.6.2.tgz#8e122f9b354fde4073763adb54fb76826dc7148e" - integrity sha512-zXTHOLgt10cMvV0Ez9S/3F8K1yn2JbGAaHF97SHAQYMlLxk3z2PCATaBvfIimYdaYj1A6qf0KbznRUFG8ZPDUw== +mjml-validator@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-validator/-/mjml-validator-4.8.1.tgz#936ffc0c8f98803ffac1028bbcdb718d614ad538" + integrity sha512-5qykc1kLILqj89Zqij6SsuKHG/jp5mjJfZWFpC8sEKIPVxBKBduz3BNSp5KABue1wW17swaXyMFhCjiFD+QRrg== dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" + "@babel/runtime" "^7.8.7" -mjml-validator@4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/mjml-validator/-/mjml-validator-4.5.0.tgz#058c41ace71b5ee821e1955fd448d9e40dec4675" - integrity sha512-Qbyf/VCk3U8ViLCu+VCwGYZVQaJAw5brKW/aXeRRHb10LdhaCF1S0JNIiNyutfnqn92QWdzYt6W+cbcEZIKa9A== +mjml-wrapper@4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml-wrapper/-/mjml-wrapper-4.8.1.tgz#93b94624bb789986d911922c4bac18b550f22843" + integrity sha512-PgOg6sEW/bXOnvMt5L2KuJCdlsOclw+GqH9Cf3gVHgw2P+7OfLIp6p+gByYTwjc4JAoUz0mfcCWdZ9HRMSCcYQ== dependencies: - babel-runtime "^6.26.0" + "@babel/runtime" "^7.8.7" lodash "^4.17.15" - warning "^3.0.0" - -mjml-wrapper@4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml-wrapper/-/mjml-wrapper-4.6.2.tgz#7bd79afeb1deeb75acb618da49f15f5cea2e5f53" - integrity sha512-jRSR43SoR7DZvygednfRiiqs+qLjPf20FHT/2RirMFbere4N+wsYQcq6Kbmn1ejq+MPIjkVucNzUif1B/7tJnQ== - dependencies: - babel-runtime "^6.26.0" - lodash "^4.17.15" - mjml-core "4.6.2" - mjml-section "4.6.2" + mjml-core "4.8.1" + mjml-section "4.8.1" mjml@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/mjml/-/mjml-4.6.2.tgz#b8dbfefa0663f5dd7f94f430738b83f3963e7bce" - integrity sha512-Uc1pT08Bxd7MOlMnYZm25uwzXABq18oCqKcqCjOrxM/YhS1n+oQQrTaggda/i40/xK9LkHVlL+VElab8iQAnjg== + version "4.8.1" + resolved "https://registry.yarnpkg.com/mjml/-/mjml-4.8.1.tgz#32b65a98c4bab7a5a1f51b784fae92c768b35b5b" + integrity sha512-jdKABiLBA1IJ0qTA5QVVsi/NN5GFtdvC1lxwdxrYV6J7dcJW7Z07j3r/GmJyOc2cznCFpJFKzfYV4Z6OZS4iyw== dependencies: - mjml-accordion "4.6.2" - mjml-body "4.6.2" - mjml-button "4.6.2" - mjml-carousel "4.6.2" - mjml-cli "4.6.2" - mjml-column "4.6.2" - mjml-core "4.6.2" - mjml-divider "4.6.2" - mjml-group "4.6.2" - mjml-head "4.6.2" - mjml-head-attributes "4.6.2" - mjml-head-breakpoint "4.6.2" - mjml-head-font "4.6.2" - mjml-head-preview "4.6.2" - mjml-head-style "4.6.2" - mjml-head-title "4.6.2" - mjml-hero "4.6.2" - mjml-image "4.6.2" - mjml-migrate "4.6.0" - mjml-navbar "4.6.2" - mjml-raw "4.6.2" - mjml-section "4.6.2" - mjml-social "4.6.2" - mjml-spacer "4.6.2" - mjml-table "4.6.2" - mjml-text "4.6.2" - mjml-validator "4.5.0" - mjml-wrapper "4.6.2" + "@babel/runtime" "^7.8.7" + mjml-accordion "4.8.1" + mjml-body "4.8.1" + mjml-button "4.8.1" + mjml-carousel "4.8.1" + mjml-cli "4.8.1" + mjml-column "4.8.1" + mjml-core "4.8.1" + mjml-divider "4.8.1" + mjml-group "4.8.1" + mjml-head "4.8.1" + mjml-head-attributes "4.8.1" + mjml-head-breakpoint "4.8.1" + mjml-head-font "4.8.1" + mjml-head-html-attributes "4.8.1" + mjml-head-preview "4.8.1" + mjml-head-style "4.8.1" + mjml-head-title "4.8.1" + mjml-hero "4.8.1" + mjml-image "4.8.1" + mjml-migrate "4.8.1" + mjml-navbar "4.8.1" + mjml-raw "4.8.1" + mjml-section "4.8.1" + mjml-social "4.8.1" + mjml-spacer "4.8.1" + mjml-table "4.8.1" + mjml-text "4.8.1" + mjml-validator "4.8.1" + mjml-wrapper "4.8.1" -mkdirp@1.x, mkdirp@~1.0.3: +mkdirp@1.x, mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mkdirp@^0.5.0, mkdirp@^0.5.5: + 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" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -3633,11 +4785,16 @@ ms@2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -ms@^2.1.1: +ms@2.1.2: version "2.1.2" - resolved "http://127.0.0.1:4873/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +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== + mysql@^2.18.1: version "2.18.1" resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717" @@ -3648,9 +4805,14 @@ mysql@^2.18.1: safe-buffer "5.1.2" sqlstring "2.3.1" +nanoid@^3.1.20: + version "3.1.20" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" + integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== + nanomatch@^1.2.9: version "1.2.13" - resolved "http://127.0.0.1:4873/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" @@ -3667,9 +4829,18 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" - resolved "http://127.0.0.1:4873/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +needle@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.6.0.tgz#24dbb55f2509e2324b4a99d61f413982013ccdbe" + integrity sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -3687,31 +4858,84 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" +node-addon-api@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239" + integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw== + +node-fetch@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-int64@^0.4.0: version "0.4.0" - resolved "http://127.0.0.1:4873/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= node-modules-regexp@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-notifier@^6.0.0: - version "6.0.0" - resolved "http://127.0.0.1:4873/node-notifier/-/node-notifier-6.0.0.tgz#cea319e06baa16deec8ce5cd7f133c4a46b68e12" - integrity sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw== +node-notifier@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.1.tgz#f86e89bbc925f2b068784b31f382afdc6ca56be1" + integrity sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA== dependencies: growly "^1.3.0" - is-wsl "^2.1.1" - semver "^6.3.0" + is-wsl "^2.2.0" + semver "^7.3.2" shellwords "^0.1.1" - which "^1.3.1" + uuid "^8.3.0" + which "^2.0.2" + +node-pre-gyp@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.17.0.tgz#5af3f7b4c3848b5ed00edc3d298ff836daae5f1d" + integrity sha512-abzZt1hmOjkZez29ppg+5gGqdPLUuJeAEwVPtHYEJgx0qzttCbcKFpxrCQn2HYbwCv2c+7JwH4BgEzFkUGpn4A== + dependencies: + detect-libc "^1.0.3" + mkdirp "^0.5.5" + needle "^2.5.2" + nopt "^4.0.3" + npm-packlist "^1.4.8" + npmlog "^4.1.2" + rc "^1.2.8" + rimraf "^2.7.1" + semver "^5.7.1" + tar "^4.4.13" + +nodemailer@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-5.0.0.tgz#bcb409eca613114e85de42646d0ce7f1fa70b716" + integrity sha512-XI4PI5L7GYcJyHkPcHlvPyRrYohNYBNRNbt1tU8PXNU3E1ADJC84a13V0vbL9AM431OP+ETacaGXAF8fGn1JvA== + +nodemailer@^3.1.1: + version "3.1.8" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-3.1.8.tgz#febfaccb4bd273678473a309c6cb4b4a2f3c48e3" + integrity sha1-/r+sy0vSc2eEc6MJxstLSi88SOM= nodemailer@^6.4.6: - version "6.4.6" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.6.tgz#d37f504f6560b36616f646a606894fe18819107f" - integrity sha512-/kJ+FYVEm2HuUlw87hjSqTss+GU35D4giOpdSfGp7DO+5h6RlJj7R94YaYHOkoxu1CSaM0d3WRBtCzwXrY6MKA== + version "6.4.17" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.17.tgz#8de98618028953b80680775770f937243a7d7877" + integrity sha512-89ps+SBGpo0D4Bi5ZrxcrCiRFaMmkCt+gItMXQGzEtZVR3uAD3QAQIDoxTWnx3ky0Dwwy/dhFrQ+6NNGXpw/qQ== + +nodemon@^2.0.6: + version "2.0.7" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.7.tgz#6f030a0a0ebe3ea1ba2a38f71bf9bab4841ced32" + integrity sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA== + dependencies: + chokidar "^3.2.2" + debug "^3.2.6" + ignore-by-default "^1.0.1" + minimatch "^3.0.4" + pstree.remy "^1.1.7" + semver "^5.7.1" + supports-color "^5.5.0" + touch "^3.1.0" + undefsafe "^2.0.3" + update-notifier "^4.1.0" nopt@^4.0.3: version "4.0.3" @@ -3721,9 +4945,23 @@ nopt@^4.0.3: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.5.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" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= + dependencies: + abbrev "1" + +normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" - resolved "http://127.0.0.1:4873/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== dependencies: hosted-git-info "^2.1.4" @@ -3733,7 +4971,7 @@ normalize-package-data@^2.5.0: normalize-path@^2.1.1: version "2.1.1" - resolved "http://127.0.0.1:4873/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" @@ -3743,20 +4981,63 @@ 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== +normalize-url@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" + integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== + +npm-bundled@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" + integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + +npm-packlist@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" + npm-run-path@^2.0.0: version "2.0.2" - resolved "http://127.0.0.1:4873/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" npm-run-path@^4.0.0: version "4.0.1" - resolved "http://127.0.0.1:4873/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + 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@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +nth-check@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125" + integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q== + dependencies: + boolbase "^1.0.0" + nth-check@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" @@ -3764,20 +5045,25 @@ nth-check@~1.0.1: dependencies: boolbase "~1.0.0" +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + nunjucks@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/nunjucks/-/nunjucks-3.2.1.tgz#f229539281e92c6ad25d8c578c9bdb41655caf83" - integrity sha512-LYlVuC1ZNSalQQkLNNPvcgPt2M9FTY9bs39mTCuFXtqh7jWbYzhDlmz2M6onPiXEhdZo+b9anRhc+uBGuJZ2bQ== + version "3.2.2" + resolved "https://registry.yarnpkg.com/nunjucks/-/nunjucks-3.2.2.tgz#45f915fef0f89fbab38c489dc85025f64859f466" + integrity sha512-KUi85OoF2NMygwODAy28Lh9qHmq5hO3rBlbkYoC8v377h4l8Pt5qFjILl0LWpMbOrZ18CzfVVUvIHUIrtED3sA== dependencies: a-sync-waterfall "^1.0.0" asap "^2.0.3" - commander "^3.0.2" + commander "^5.1.0" optionalDependencies: chokidar "^3.3.0" nwsapi@^2.2.0: version "2.2.0" - resolved "http://127.0.0.1:4873/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== oauth-sign@~0.9.0: @@ -3785,9 +5071,19 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +object-assign@^4, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= + object-copy@^0.1.0: version "0.1.0" - resolved "http://127.0.0.1:4873/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" @@ -3796,14 +5092,14 @@ object-copy@^0.1.0: object-visit@^1.0.0: version "1.0.1" - resolved "http://127.0.0.1:4873/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" object.pick@^1.3.0: version "1.3.0" - resolved "http://127.0.0.1:4873/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" @@ -3817,7 +5113,7 @@ on-finished@^2.3.0, on-finished@~2.3.0: on-headers@~1.0.2: version "1.0.2" - resolved "http://127.0.0.1:4873/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== once@^1.3.0, once@^1.3.1, once@^1.4.0: @@ -3828,15 +5124,27 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: wrappy "1" onetime@^5.1.0: - version "5.1.0" - resolved "http://127.0.0.1:4873/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" - integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== + 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" +opencollective-postinstall@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" + integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== + +opn@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-6.0.0.tgz#3c5b0db676d5f97da1233d1ed42d182bc5a27d2d" + integrity sha512-I9PKfIZC+e4RXZ/qr1RhgyCnGgYX0UEIlXgWnCOVACIvFgaC9rz6Won7xbdhoHrd8IIhV7YEpHjreNUNkqCGkQ== + dependencies: + is-wsl "^1.1.0" + optionator@^0.8.1: version "0.8.3" - resolved "http://127.0.0.1:4873/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" @@ -3846,6 +5154,18 @@ optionator@^0.8.1: 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" + 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" + os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -3864,21 +5184,21 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + p-each-series@^2.1.0: - version "2.1.0" - resolved "http://127.0.0.1:4873/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" - integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" + integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== p-finally@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-finally@^2.0.0: - version "2.0.1" - resolved "http://127.0.0.1:4873/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" - integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== - p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -3895,7 +5215,7 @@ p-locate@^3.0.0: p-locate@^4.1.0: version "4.1.0" - resolved "http://127.0.0.1:4873/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + 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" @@ -3905,27 +5225,85 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -param-case@2.1.x: +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +param-case@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= dependencies: no-case "^2.2.0" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + parse-json@^5.0.0: - version "5.0.0" - resolved "http://127.0.0.1:4873/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" - integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" + json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse5@5.1.0: - version "5.1.0" - resolved "http://127.0.0.1:4873/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" - integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== +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@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" + integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA== + dependencies: + "@types/node" "*" + +parse5@^6.0.0, parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + dependencies: + better-assert "~1.0.0" parseurl@~1.3.3: version "1.3.3" @@ -3934,7 +5312,7 @@ parseurl@~1.3.3: pascalcase@^0.1.1: version "0.1.1" - resolved "http://127.0.0.1:4873/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= path-exists@^3.0.0: @@ -3944,7 +5322,7 @@ path-exists@^3.0.0: path-exists@^4.0.0: version "4.0.0" - resolved "http://127.0.0.1:4873/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + 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: @@ -3959,12 +5337,12 @@ path-key@^2.0.0, path-key@^2.0.1: path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "http://127.0.0.1:4873/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.6: version "1.0.6" - resolved "http://127.0.0.1:4873/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== path-to-regexp@0.1.7: @@ -3972,67 +5350,92 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-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== + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.0.7: +picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + pirates@^4.0.1: version "4.0.1" - resolved "http://127.0.0.1:4873/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== dependencies: node-modules-regexp "^1.0.0" pkg-dir@^4.2.0: version "4.2.0" - resolved "http://127.0.0.1:4873/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + 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" -pn@^1.1.0: - version "1.1.0" - resolved "http://127.0.0.1:4873/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== - posix-character-classes@^0.1.0: version "0.1.1" - resolved "http://127.0.0.1:4873/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +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== + prelude-ls@~1.1.2: version "1.1.2" - resolved "http://127.0.0.1:4873/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -pretty-format@^25.2.1, pretty-format@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/pretty-format/-/pretty-format-25.4.0.tgz#c58801bb5c4926ff4a677fe43f9b8b99812c7830" - integrity sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ== +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +pretty-format@^26.0.0, pretty-format@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== dependencies: - "@jest/types" "^25.4.0" + "@jest/types" "^26.6.2" ansi-regex "^5.0.0" ansi-styles "^4.0.0" - react-is "^16.12.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== +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== + prompts@^2.0.1: - version "2.3.2" - resolved "http://127.0.0.1:4873/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" - integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA== + version "2.4.0" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" + integrity sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ== dependencies: kleur "^3.0.3" - sisteransi "^1.0.4" + sisteransi "^1.0.5" proto-list@~1.2.1: version "1.2.4" @@ -4057,9 +5460,14 @@ psl@^1.1.28: resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== +pstree.remy@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" + integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== + pump@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== dependencies: end-of-stream "^1.1.0" @@ -4070,11 +5478,23 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +pupa@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" + integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== + dependencies: + escape-goat "^2.0.0" + qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@^6.9.4: + version "6.9.6" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" + integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== + qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -4082,7 +5502,7 @@ qs@~6.5.2: random-bytes@~1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" + resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= range-parser@~1.2.1: @@ -4100,23 +5520,42 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -react-is@^16.12.0: - version "16.13.1" - resolved "http://127.0.0.1:4873/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-is@^17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" + integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== read-pkg-up@^7.0.1: version "7.0.1" - resolved "http://127.0.0.1:4873/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== dependencies: find-up "^4.1.0" read-pkg "^5.2.0" type-fest "^0.8.1" +read-pkg@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" + integrity sha1-ljYlN48+HE1IyFhytabsfV0JMjc= + dependencies: + normalize-package-data "^2.3.2" + parse-json "^4.0.0" + pify "^3.0.0" + read-pkg@^5.2.0: version "5.2.0" - resolved "http://127.0.0.1:4873/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== dependencies: "@types/normalize-package-data" "^2.4.0" @@ -4124,7 +5563,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@2.3.7: +readable-stream@2.3.7, readable-stream@^2.0.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -4137,7 +5576,7 @@ readable-stream@2.3.7: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1: +readable-stream@^3.1.1, 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== @@ -4146,38 +5585,33 @@ readable-stream@^3.1.1: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readdirp@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17" - integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ== +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== dependencies: - picomatch "^2.0.7" - -realpath-native@^2.0.0: - version "2.0.0" - resolved "http://127.0.0.1:4873/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866" - integrity sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q== + picomatch "^2.2.1" redis-commands@^1.5.0: - version "1.5.0" - resolved "http://127.0.0.1:4873/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785" - integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg== + version "1.6.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.6.0.tgz#36d4ca42ae9ed29815cdb30ad9f97982eba1ce23" + integrity sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ== redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" - resolved "http://127.0.0.1:4873/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= redis-parser@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= dependencies: redis-errors "^1.0.0" redis@^3.0.2: version "3.0.2" - resolved "http://127.0.0.1:4873/redis/-/redis-3.0.2.tgz#bd47067b8a4a3e6a2e556e57f71cc82c7360150a" + resolved "https://registry.yarnpkg.com/redis/-/redis-3.0.2.tgz#bd47067b8a4a3e6a2e556e57f71cc82c7360150a" integrity sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ== dependencies: denque "^1.4.1" @@ -4185,56 +5619,75 @@ redis@^3.0.2: redis-errors "^1.2.0" redis-parser "^3.0.0" -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== +regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" - resolved "http://127.0.0.1:4873/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" -relateurl@0.2.x: +regexpp@^3.0.0, regexpp@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== + +registry-auth-token@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" + integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== + dependencies: + rc "^1.2.8" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +relateurl@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= remove-trailing-separator@^1.0.1: version "1.1.0" - resolved "http://127.0.0.1:4873/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: version "1.1.3" - resolved "http://127.0.0.1:4873/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== repeat-string@^1.6.1: version "1.6.1" - resolved "http://127.0.0.1:4873/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -request-promise-core@1.1.3: - version "1.1.3" - resolved "http://127.0.0.1:4873/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" - integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== +request-promise-core@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" + integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== dependencies: - lodash "^4.17.15" + lodash "^4.17.19" -request-promise-native@^1.0.7: - version "1.0.8" - resolved "http://127.0.0.1:4873/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" - integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== +request-promise-native@^1.0.8: + version "1.0.9" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" + integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== dependencies: - request-promise-core "1.1.3" + request-promise-core "1.1.4" stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.88.0: +request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -4265,6 +5718,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" @@ -4272,75 +5730,112 @@ require-main-filename@^2.0.0: resolve-cwd@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + 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 "http://127.0.0.1:4873/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve-url@^0.2.1: version "0.2.1" - resolved "http://127.0.0.1:4873/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.7: - version "1.1.7" - resolved "http://127.0.0.1:4873/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - -resolve@1.x, resolve@^1.10.0, resolve@^1.15.1, resolve@^1.3.2: - version "1.17.0" - resolved "http://127.0.0.1:4873/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== +resolve@^1.10.0, resolve@^1.18.1: + version "1.19.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" + integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== dependencies: + is-core-module "^2.1.0" path-parse "^1.0.6" +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + ret@~0.1.10: version "0.1.15" - resolved "http://127.0.0.1:4873/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -rimraf@^3.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.5.2, rimraf@^2.6.3, rimraf@^2.7.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.0, rimraf@^3.0.2: version "3.0.2" - resolved "http://127.0.0.1:4873/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" rsvp@^4.8.4: version "4.8.5" - resolved "http://127.0.0.1:4873/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== +run-parallel@^1.1.9: + version "1.1.10" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef" + integrity sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw== + +rxjs@^6.5.2: + version "6.6.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" + integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== + dependencies: + tslib "^1.9.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.0, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex@^1.1.0: version "1.1.0" - resolved "http://127.0.0.1:4873/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@^2.1.2, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sane@^4.0.3: version "4.1.0" - resolved "http://127.0.0.1:4873/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== dependencies: "@cnakazawa/watch" "^1.0.3" @@ -4353,21 +5848,40 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -saxes@^3.1.9: - version "3.1.11" - resolved "http://127.0.0.1:4873/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" - integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== - dependencies: - xmlchars "^2.1.1" +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +saxes@^5.0.0: + 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-diff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" + integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== + dependencies: + semver "^6.3.0" + +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@6.x, semver@^6.0.0, semver@^6.3.0: +semver@7.x, semver@^7.2.1, semver@^7.3.2: + version "7.3.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" + +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" - resolved "http://127.0.0.1:4873/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== send@0.17.1: @@ -4399,14 +5913,14 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" -set-blocking@^2.0.0: +set-blocking@^2.0.0, 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= set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" - resolved "http://127.0.0.1:4873/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== dependencies: extend-shallow "^2.0.1" @@ -4428,7 +5942,7 @@ shebang-command@^1.2.0: shebang-command@^2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + 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" @@ -4440,12 +5954,12 @@ shebang-regex@^1.0.0: shebang-regex@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shellwords@^0.1.1: version "0.1.1" - resolved "http://127.0.0.1:4873/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== sigmund@^1.0.1: @@ -4455,27 +5969,52 @@ sigmund@^1.0.1: signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" - resolved "http://127.0.0.1:4873/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== -sisteransi@^1.0.4: +sisteransi@^1.0.5: version "1.0.5" - resolved "http://127.0.0.1:4873/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + 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 "http://127.0.0.1:4873/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + slick@^1.12.2: version "1.12.2" resolved "https://registry.yarnpkg.com/slick/-/slick-1.12.2.tgz#bd048ddb74de7d1ca6915faa4a57570b3550c2d7" integrity sha1-vQSN23TefRymkV+qSldXCzVQwtc= +smtp-connection@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-4.0.2.tgz#d9dd68d38569f3ad9265473670d09d8f3ea518db" + integrity sha1-2d1o04Vp862SZUc2cNCdjz6lGNs= + dependencies: + nodemailer "^3.1.1" + +smtp-server@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/smtp-server/-/smtp-server-3.5.0.tgz#eb2e7bd52f26b4136b9dfc2c9fa0ba70e18cdc81" + integrity sha512-7FUg09H1VmqMRlUq/QdkPxn/NK8VCFw7GMU5rdWWDbS00wbLhjRBe3Lme+AamjDSmVoP6e/WqFqsa7jVI+69pg== + dependencies: + base32.js "0.1.0" + ipv6-normalize "1.0.1" + nodemailer "5.0.0" + snapdragon-node@^2.0.1: version "2.1.1" - resolved "http://127.0.0.1:4873/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" @@ -4484,14 +6023,14 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" - resolved "http://127.0.0.1:4873/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" - resolved "http://127.0.0.1:4873/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" @@ -4503,9 +6042,55 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +socket.io-adapter@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" + integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== + +socket.io-client@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" + integrity sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA== + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.3.1" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6" + integrity sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg== + dependencies: + component-emitter "~1.3.0" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b" + integrity sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w== + dependencies: + debug "~4.1.0" + engine.io "~3.3.1" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.2.0" + socket.io-parser "~3.3.0" + source-map-resolve@^0.5.0: version "0.5.3" - resolved "http://127.0.0.1:4873/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: atob "^2.1.2" @@ -4514,22 +6099,22 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.17, source-map-support@^0.5.6: - version "0.5.18" - resolved "http://127.0.0.1:4873/source-map-support/-/source-map-support-0.5.18.tgz#f5f33489e270bd7f7d7e7b8debf283f3a4066960" - integrity sha512-9luZr/BZ2QeU6tO2uG8N2aZpVSli4TSAOAqFOyTO51AJcD9P99c0K1h6dD6r6qo5dyT44BR5exweOaLLeldTkQ== +source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" source-map-url@^0.4.0: version "0.4.0" - resolved "http://127.0.0.1:4873/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" - resolved "http://127.0.0.1:4873/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + 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.0, source-map@~0.6.1: @@ -4539,45 +6124,55 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: source-map@^0.7.3: version "0.7.3" - resolved "http://127.0.0.1:4873/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== +spawn-command@^0.0.2-1: + version "0.0.2-1" + resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" + integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A= + spdx-correct@^3.0.0: - version "3.1.0" - resolved "http://127.0.0.1:4873/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: version "2.3.0" - resolved "http://127.0.0.1:4873/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "http://127.0.0.1:4873/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "http://127.0.0.1:4873/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + version "3.0.7" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65" + integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" - resolved "http://127.0.0.1:4873/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" +sprintf-js@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + sprintf-js@~1.0.2: version "1.0.3" - resolved "http://127.0.0.1:4873/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sqlstring@2.3.1: @@ -4600,14 +6195,16 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -stack-utils@^1.0.1: - version "1.0.2" - resolved "http://127.0.0.1:4873/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" - integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== +stack-utils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.3.tgz#cd5f030126ff116b78ccb3c027fe302713b61277" + integrity sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw== + dependencies: + escape-string-regexp "^2.0.0" static-extend@^0.1.1: version "0.1.2" - resolved "http://127.0.0.1:4873/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" @@ -4620,16 +6217,33 @@ static-extend@^0.1.1: stealthy-require@^1.1.1: version "1.1.1" - resolved "http://127.0.0.1:4873/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= -string-length@^3.1.0: - version "3.1.0" - resolved "http://127.0.0.1:4873/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837" - integrity sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA== +string-length@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" + integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw== dependencies: - astral-regex "^1.0.0" - strip-ansi "^5.2.0" + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" @@ -4640,9 +6254,9 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0: +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: version "4.2.0" - resolved "http://127.0.0.1:4873/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== dependencies: emoji-regex "^8.0.0" @@ -4663,6 +6277,20 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -4672,56 +6300,126 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: strip-ansi@^6.0.0: version "6.0.0" - resolved "http://127.0.0.1:4873/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== dependencies: ansi-regex "^5.0.0" strip-bom@^4.0.0: version "4.0.0" - resolved "http://127.0.0.1:4873/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== strip-eof@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= strip-final-newline@^2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -supports-color@^5.3.0: +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== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +superagent@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-6.1.0.tgz#09f08807bc41108ef164cfb4be293cebd480f4a6" + integrity sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg== + dependencies: + component-emitter "^1.3.0" + cookiejar "^2.1.2" + debug "^4.1.1" + fast-safe-stringify "^2.0.7" + form-data "^3.0.0" + formidable "^1.2.2" + methods "^1.1.2" + mime "^2.4.6" + qs "^6.9.4" + readable-stream "^3.6.0" + semver "^7.3.2" + +supertest@^6.0.0: + version "6.1.2" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-6.1.2.tgz#1679c234b139eed93911c185b67f689348fc2453" + integrity sha512-hZ8bu3TebxCYQ40mF6/2ou58EEG5jxo1AbsE1vprqXo3emkmqbQMcQrF7acsQteOjYlkExSvYOAQ/feTE9n7uA== + dependencies: + methods "^1.1.2" + superagent "^6.1.0" + +supports-color@^5.3.0, supports-color@^5.5.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@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + supports-color@^7.0.0, supports-color@^7.1.0: - version "7.1.0" - resolved "http://127.0.0.1:4873/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + 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-hyperlinks@^2.0.0: version "2.1.0" - resolved "http://127.0.0.1:4873/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== dependencies: has-flag "^4.0.0" supports-color "^7.0.0" -symbol-tree@^3.2.2: +symbol-tree@^3.2.4: version "3.2.4" - resolved "http://127.0.0.1:4873/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +table@^6.0.4: + version "6.0.7" + resolved "https://registry.yarnpkg.com/table/-/table-6.0.7.tgz#e45897ffbcc1bcf9e8a87bf420f2c9e5a7a52a34" + integrity sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g== + dependencies: + ajv "^7.0.2" + lodash "^4.17.20" + slice-ansi "^4.0.0" + string-width "^4.2.0" + +tar@^4.4.13: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.8.6" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +term-size@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" + integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== + terminal-link@^2.0.0: version "2.1.1" - resolved "http://127.0.0.1:4873/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + 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" @@ -4729,38 +6427,53 @@ terminal-link@^2.0.0: test-exclude@^6.0.0: version "6.0.0" - resolved "http://127.0.0.1:4873/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + 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" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + throat@^5.0.0: version "5.0.0" - resolved "http://127.0.0.1:4873/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== tmpl@1.0.x: version "1.0.4" - resolved "http://127.0.0.1:4873/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + to-fast-properties@^2.0.0: version "2.0.0" - resolved "http://127.0.0.1:4873/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-object-path@^0.3.0: version "0.3.0" - resolved "http://127.0.0.1:4873/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: kind-of "^3.0.2" +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + to-regex-range@^2.1.0: version "2.1.1" - resolved "http://127.0.0.1:4873/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" @@ -4775,7 +6488,7 @@ to-regex-range@^5.0.1: to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" - resolved "http://127.0.0.1:4873/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" @@ -4788,6 +6501,13 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +touch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" + integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== + dependencies: + nopt "~1.0.10" + tough-cookie@^2.3.3, tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -4798,48 +6518,73 @@ tough-cookie@^2.3.3, tough-cookie@~2.5.0: tough-cookie@^3.0.1: version "3.0.1" - resolved "http://127.0.0.1:4873/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== dependencies: ip-regex "^2.1.0" psl "^1.1.28" punycode "^2.1.1" -tr46@^1.0.1: - version "1.0.1" - resolved "http://127.0.0.1:4873/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= +tr46@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" + integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== dependencies: - punycode "^2.1.0" + punycode "^2.1.1" -ts-jest@^25.4.0: - version "25.4.0" - resolved "http://127.0.0.1:4873/ts-jest/-/ts-jest-25.4.0.tgz#5ad504299f8541d463a52e93e5e9d76876be0ba4" - integrity sha512-+0ZrksdaquxGUBwSdTIcdX7VXdwLIlSRsyjivVA9gcO+Cvr6ByqDhu/mi5+HCcb6cMkiQp5xZ8qRO7/eCqLeyw== +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-jest@^26.1.1: + version "26.4.4" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.4.4.tgz#61f13fb21ab400853c532270e52cc0ed7e502c49" + integrity sha512-3lFWKbLxJm34QxyVNNCgXX1u4o/RV0myvA2y2Bxm46iGIjKlaY0own9gIckbjZJPn+WaJEnfPPJ20HHGpoq4yg== dependencies: + "@types/jest" "26.x" bs-logger "0.x" buffer-from "1.x" fast-json-stable-stringify "2.x" + jest-util "^26.1.0" json5 "2.x" lodash.memoize "4.x" make-error "1.x" - micromatch "4.x" mkdirp "1.x" - resolve "1.x" - semver "6.x" - yargs-parser "18.x" + semver "7.x" + yargs-parser "20.x" -ts-node@^8.9.0: - version "8.9.0" - resolved "http://127.0.0.1:4873/ts-node/-/ts-node-8.9.0.tgz#d7bf7272dcbecd3a2aa18bd0b96c7d2f270c15d4" - integrity sha512-rwkXfOs9zmoHrV8xE++dmNd6ZIS+nmHHCxcV53ekGJrxFLMbp+pizpPS07ARvhwneCIECPppOwbZHvw9sQtU4w== +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" +tslib@^1.8.1, tslib@^1.9.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslog@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.1.0.tgz#e169c974c297bdec160a17a4dc19acd86f65b4e8" + integrity sha512-q3Itu9GGBd9ijZ3HF+lUB6E4N+qlGxVpGxBTIIMuMSQbYDE3gg/TOCsywtKFxVtqvmS9aCyKw/xeUxfvrx+oMQ== + dependencies: + source-map-support "^0.5.19" + +tsutils@^3.17.1: + version "3.19.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.19.1.tgz#d8566e0c51c82f32f9c25a4d367cd62409a547a9" + integrity sha512-GEdoBf5XI324lu7ycad7s6laADfnAqCw6wLGI+knxvw9vsIYBaJfYdmeCEG3FMMUiSm3OGgNb+m6utsWf5h9Vw== + dependencies: + tslib "^1.8.1" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -4852,31 +6597,38 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +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-check@~0.3.2: version "0.3.2" - resolved "http://127.0.0.1:4873/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + 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 "http://127.0.0.1:4873/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + 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.11.0: version "0.11.0" - resolved "http://127.0.0.1:4873/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== type-fest@^0.6.0: version "0.6.0" - resolved "http://127.0.0.1:4873/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== type-fest@^0.8.1: version "0.8.1" - resolved "http://127.0.0.1:4873/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== type-is@~1.6.17, type-is@~1.6.18: @@ -4889,34 +6641,38 @@ type-is@~1.6.17, type-is@~1.6.18: typedarray-to-buffer@^3.1.5: version "3.1.5" - resolved "http://127.0.0.1:4873/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + 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" -typescript@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@^4.0.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" + integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== -uglify-js@3.4.x: - version "3.4.10" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" - integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw== - dependencies: - commander "~2.19.0" - source-map "~0.6.1" +uglify-js@^3.5.1: + version "3.12.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.12.5.tgz#83241496087c640efe9dfc934832e71725aba008" + integrity sha512-SgpgScL4T7Hj/w/GexjnBHi3Ien9WS1Rpfg5y91WXMj9SY997ZCQU76mH4TpLwwfmMvoOU8wiaRkIf6NaH3mtg== uid-safe@~2.1.5: version "2.1.5" - resolved "http://127.0.0.1:4873/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" + resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" integrity sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA== dependencies: random-bytes "~1.0.0" +undefsafe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" + integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== + dependencies: + debug "^2.2.0" + union-value@^1.0.0: version "1.0.1" - resolved "http://127.0.0.1:4873/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== dependencies: arr-union "^3.1.0" @@ -4924,6 +6680,13 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -4931,32 +6694,58 @@ unpipe@1.0.0, unpipe@~1.0.0: unset-value@^1.0.0: version "1.0.0" - resolved "http://127.0.0.1:4873/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" isobject "^3.0.0" +update-notifier@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" + integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== + dependencies: + boxen "^4.2.0" + chalk "^3.0.0" + configstore "^5.0.1" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.3.1" + is-npm "^4.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.0.0" + pupa "^2.0.1" + semver-diff "^3.1.1" + xdg-basedir "^4.0.0" + upper-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + 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" urix@^0.1.0: version "0.1.0" - resolved "http://127.0.0.1:4873/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + use@^3.1.0: version "3.1.1" - resolved "http://127.0.0.1:4873/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== util-deprecate@^1.0.1, util-deprecate@~1.0.1: @@ -4969,39 +6758,52 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uue@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/uue/-/uue-3.1.2.tgz#e99368414e87200012eb37de4dbaebaa1c742ad2" + integrity sha512-axKLXVqwtdI/czrjG0X8hyV1KLgeWx8F4KvSbvVCnS+RUvsQMGRjx0kfuZDXXqj0LYvVJmx3B9kWlKtEdRrJLg== + dependencies: + escape-string-regexp "~1.0.5" + extend "~3.0.0" + uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== +uuid@^8.0.0, uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -v8-to-istanbul@^4.1.3: - version "4.1.3" - resolved "http://127.0.0.1:4873/v8-to-istanbul/-/v8-to-istanbul-4.1.3.tgz#22fe35709a64955f49a08a7c7c959f6520ad6f20" - integrity sha512-sAjOC+Kki6aJVbUOXJbcR0MnbfjvBzwKZazEJymA2IX49uoOdEdk+4fBq5cXgYgiyKtAyrrJNtBZdOeDIF+Fng== +v8-compile-cache@^2.0.3: + version "2.2.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" + integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q== + +v8-to-istanbul@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz#5b95cef45c0f83217ec79f8fc7ee1c8b486aee07" + integrity sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" source-map "^0.7.3" -valid-data-url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/valid-data-url/-/valid-data-url-2.0.0.tgz#2220fa9f8d4e761ebd3f3bb02770f1212b810537" - integrity sha512-dyCZnv3aCey7yfTgIqdZanKl7xWAEEKCbgmR7SKqyK6QT/Z07ROactrgD1eA37C69ODRj7rNOjzKWVPh0EUjBA== +valid-data-url@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/valid-data-url/-/valid-data-url-3.0.1.tgz#826c1744e71b5632e847dd15dbd45b9fb38aa34f" + integrity sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA== validate-npm-package-license@^3.0.1: version "3.0.4" - resolved "http://127.0.0.1:4873/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -vary@~1.1.2: +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= @@ -5015,83 +6817,76 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -w3c-hr-time@^1.0.1: +w3c-hr-time@^1.0.2: version "1.0.2" - resolved "http://127.0.0.1:4873/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + 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@^1.1.2: - version "1.1.2" - resolved "http://127.0.0.1:4873/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" - integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== +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: - domexception "^1.0.1" - webidl-conversions "^4.0.2" xml-name-validator "^3.0.0" walker@^1.0.7, walker@~1.0.5: version "1.0.7" - resolved "http://127.0.0.1:4873/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= dependencies: makeerror "1.0.x" -warning@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" - integrity sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w= +web-resource-inliner@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/web-resource-inliner/-/web-resource-inliner-5.0.0.tgz#ac30db8096931f20a7c1b3ade54ff444e2e20f7b" + integrity sha512-AIihwH+ZmdHfkJm7BjSXiEClVt4zUFqX4YlFAzjL13wLtDuUneSaFvDBTbdYRecs35SiU7iNKbMnN+++wVfb6A== dependencies: - loose-envify "^1.0.0" - -web-resource-inliner@^4.3.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/web-resource-inliner/-/web-resource-inliner-4.3.4.tgz#07e1b4bcbcbee1021251b018e902bac5713f1be0" - integrity sha512-agVAgRhOOi4GVlvKK34oM23tDgH8390HfLnZY2HZl8OFBwKNvUJkH7t89AT2iluQP8w9VHAAKX6Z8EN7/9tqKA== - dependencies: - async "^3.1.0" - chalk "^2.4.2" - datauri "^2.0.0" + ansi-colors "^4.1.1" + escape-goat "^3.0.0" htmlparser2 "^4.0.0" - lodash.unescape "^4.0.1" - request "^2.88.0" - safer-buffer "^2.1.2" - valid-data-url "^2.0.0" - xtend "^4.0.2" + mime "^2.4.6" + node-fetch "^2.6.0" + valid-data-url "^3.0.0" -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "http://127.0.0.1:4873/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== +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== -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: +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 "http://127.0.0.1:4873/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + 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.2.0, whatwg-mimetype@^2.3.0: +whatwg-mimetype@^2.3.0: version "2.3.0" - resolved "http://127.0.0.1:4873/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== -whatwg-url@^7.0.0: - version "7.1.0" - resolved "http://127.0.0.1:4873/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== +whatwg-url@^8.0.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.4.0.tgz#50fb9615b05469591d2b2bd6dfaed2942ed72837" + integrity sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw== dependencies: lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" + tr46 "^2.0.2" + webidl-conversions "^6.1.0" which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@^1.2.9, which@^1.3.1: +which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -5100,14 +6895,33 @@ which@^1.2.9, which@^1.3.1: which@^2.0.1, which@^2.0.2: version "2.0.2" - resolved "http://127.0.0.1:4873/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + 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: +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + +wildstring@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/wildstring/-/wildstring-1.0.9.tgz#82a696d5653c7d4ec9ba716859b6b53aba2761c5" + integrity sha1-gqaW1WU8fU7JunFoWba1OronYcU= + +word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" - resolved "http://127.0.0.1:4873/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + 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@^5.1.0: @@ -5121,13 +6935,22 @@ wrap-ansi@^5.1.0: wrap-ansi@^6.2.0: version "6.2.0" - resolved "http://127.0.0.1:4873/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== dependencies: ansi-styles "^4.0.0" string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^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" @@ -5135,7 +6958,7 @@ wrappy@1: write-file-atomic@^3.0.0: version "3.0.3" - resolved "http://127.0.0.1:4873/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + 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" @@ -5143,43 +6966,67 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@^7.0.0, ws@^7.2.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" - integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ== +ws@^7.2.3: + version "7.4.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.2.tgz#782100048e54eb36fe9843363ab1c68672b261dd" + integrity sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA== + +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== + dependencies: + async-limiter "~1.0.0" + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== xml-name-validator@^3.0.0: version "3.0.0" - resolved "http://127.0.0.1:4873/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xmlchars@^2.1.1: +xmlchars@^2.2.0: version "2.2.0" - resolved "http://127.0.0.1:4873/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xtend@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + version "4.0.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4" + integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ== + +y18n@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" + integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= -yargs-parser@18.x, yargs-parser@^18.1.1: - version "18.1.3" - resolved "http://127.0.0.1:4873/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +yallist@^3.0.0, yallist@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +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.x, yargs-parser@^20.2.2: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== yargs-parser@^13.1.2: version "13.1.2" @@ -5189,6 +7036,14 @@ yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs@^13.3.0: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" @@ -5205,10 +7060,10 @@ yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.2" -yargs@^15.3.1: - version "15.3.1" - resolved "http://127.0.0.1:4873/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== +yargs@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== dependencies: cliui "^6.0.0" decamelize "^1.2.0" @@ -5220,9 +7075,35 @@ yargs@^15.3.1: string-width "^4.2.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^18.1.1" + yargs-parser "^18.1.2" + +yargs@^16.1.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" + +yauzl@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= yn@3.1.1: version "3.1.1" - resolved "http://127.0.0.1:4873/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==