diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 8d87b1d..0000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/* diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 6f04d5d..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,30 +0,0 @@ -module.exports = { - 'env': { - 'browser': true, - 'node': true, - 'es6': true, - }, - 'extends': [ - 'google', - 'plugin:security/recommended' - ], - plugins: [ - 'security' - ], - 'globals': { - 'Atomics': 'readonly', - 'SharedArrayBuffer': 'readonly', - }, - 'parserOptions': { - 'ecmaVersion': 2018, - }, - 'rules': { - "require-jsdoc" : 0, - "valid-jsdoc" : 0, - "max-len" : ["error", { "code": 125 ,"ignoreTemplateLiterals": true},], - "no-unused-vars" : 0, - "no-var" : 0, - "prefer-const":0, - "quotes": 0 - }, -}; diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..593d759 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,14 @@ +{ + "env": { + "commonjs": true, + "es2021": true, + "node": true + }, + "extends": ["airbnb-base"], + "parserOptions": { + "ecmaVersion": 12 + }, + "rules": { + "no-console": "off" + } +} diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..f4b5e4d --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "arrowParens": "always", + "singleQuote": true, + "trailingComma": "all" +} diff --git a/Dockerfile b/Dockerfile index f49610a..95a3a22 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ WORKDIR /src RUN npm install ARG viewer ARG fork -RUN git clone https://github.com/${fork:-camicroscope}/camicroscope.git --branch=${viewer:-master} +#RUN git clone https://github.com/${fork:-camicroscope}/camicroscope.git --branch=${viewer:-master} EXPOSE 8010 RUN chgrp -R 0 /src && \ diff --git a/README.md b/README.md index cf84b4e..bf9e80a 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ The CSP headers are generated from `contentSecurityPolicy.json`. ## User property variables These are set in userFunction and injected into the token. -userType -- Null, Editor, Admin as userTypes (e.g. Admin can create users, Editor can create marks, Null can't create anything except logs) +userType -- Null, Editor, Admin as user roles (e.g. Admin can create users, Editor can create marks, Null can't create anything except logs). The roles are hierarchical, i.e. a higher role has all rights that the roles of its juniors. userFilter -- list of values which must be present in given field in filtered data responses diff --git a/caracal.js b/caracal.js index 8516348..03c1913 100644 --- a/caracal.js +++ b/caracal.js @@ -1,211 +1,313 @@ +/* eslint-disable object-shorthand */ +/* eslint-disable func-names */ +/** + * object-shorthand and func-names is disabled because arrow functions (preferred by eslint) and + * traditional functions are not the same. The main difference comes from the fact that arrow + * functions lexically. + * + * Therefore before due testing, it is not safe to migrate to shorthands with arrow functions. + * + * @link https://dmitripavlutin.com/differences-between-arrow-and-regular-functions/ + */ + +/** load environment variables */ require('dotenv').config(); -const express = require('express'); -var proxy = require('http-proxy-middleware'); +/** + * NodeJS Modules + */ const https = require('https'); -var cookieParser = require('cookie-parser'); -var throng = require('throng'); -var routeConfig = require("./routes.json"); -var cspConfig = require("./contentSecurityPolicy.json"); -var helmet = require('helmet'); const fs = require('fs'); -// handlers -const auth = require('./handlers/authHandlers.js'); -const monitor = require('./handlers/monitorHandlers.js'); -const userFunction = require('./handlers/userFunction.js'); -const iipHandler = require('./handlers/iipHandler.js'); -const proxyHandler = require('./handlers/proxyHandler.js'); -const permissionHandler = require('./handlers/permssionHandler.js'); -const dataHandlers = require('./handlers/dataHandlers.js'); -const sanitizeBody = require('./handlers/sanitizeHandler.js'); -const DataSet = require('./handlers/datasetHandler.js'); -const Model = require('./handlers/modelTrainer.js'); -const DataTransformationHandler = require('./handlers/dataTransformationHandler.js'); -// TODO validation of data +/** + * NPM Modules + * + * @todo: proxy configuraiton + */ +const throng = require('throng'); +const helmet = require('helmet'); +const express = require('express'); +// const proxy = require('http-proxy-middleware'); +const cookieParser = require('cookie-parser'); -const {connector} = require("./service/database/connector"); +/** + * Route Mappings and Content Security Policy + */ +const cspConfig = require('./contentSecurityPolicy.json'); +const routeConfig = require('./routes.json'); -var WORKERS = process.env.NUM_THREADS || 4; +/** + * Certificate path configurations + */ +const sslPath = { + privateKey: './ssl/privatekey.pem', + certificate: './ssl/certificate.pem', +}; -var PORT = process.env.PORT || 4010; +/** + * Application Handlers + * + * permissionHandlers => to be elimiated as RBAC is implemented + */ +const auth = require('./handlers/authHandlers'); +const monitor = require('./handlers/monitorHandlers'); +const userFunction = require('./handlers/userFunction'); +const iipHandler = require('./handlers/iipHandler'); +const proxyHandler = require('./handlers/proxyHandler'); +// const permissionHandler = require('./handlers/permssionHandler'); +const dataHandlers = require('./handlers/dataHandlers'); +const sanitizeBody = require('./handlers/sanitizeHandler'); +const DataSet = require('./handlers/datasetHandler'); +const Model = require('./handlers/modelTrainer'); +const DataTransformationHandler = require('./handlers/dataTransformationHandler'); -var MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost'; +/** + * Application Services + */ +const { connector } = require('./service/database/connector'); +const { + roleStatusCheck, + initializeRolesService, +} = require('./service/roles/definitions'); +const { RoleProcessor } = require('./service/roles/middleware'); +const { roleRoutes } = require('./service/roles/routes'); -var DISABLE_CSP = process.env.DISABLE_CSP || false; +/** + * Application Constants based on environment + * + * PORT => to listen for HTTP requests + * WORKERS => Number of workers / instances of application that are launched + * MONGO_URI => connection string for mongodb database + * DISABLE_CSP => true to disable content security policy + */ +const PORT = process.env.PORT || 4010; +const WORKERS = process.env.NUM_THREADS || 1; +const MONGO_URI = process.env.MONGO_URI || 'mongodb://localhost'; +const DISABLE_CSP = process.env.DISABLE_CSP || false; +/** express.js configurations */ const app = express(); app.use(cookieParser()); if (!DISABLE_CSP) { - app.use(helmet.contentSecurityPolicy({ - directives: cspConfig, - })); + app.use( + helmet.contentSecurityPolicy({ + directives: cspConfig, + }), + ); } -// handle non-json raw body for post -app.use(function(req, res, next) { - var data = ''; +/** parse binary data into request.body */ +app.use((req, res, next) => { + let data = ''; req.setEncoding(null); - req.on('data', function(chunk) { + req.on('data', (chunk) => { data += chunk; }); - req.on('end', function() { + + req.on('end', () => { req.body = data; next(); }); }); -// auth related services -app.get('/auth/Token/check', auth.jwkTokenTrade(auth.CLIENT, auth.PRIKEY, userFunction)); -app.get('/auth/Token/renew', auth.tokenTrade(auth.PUBKEY, auth.PRIKEY, userFunction)); +/** routes for authentication */ +app.get( + '/auth/Token/check', + auth.jwkTokenTrade(auth.CLIENT, auth.PRIKEY, userFunction), +); +app.get( + '/auth/Token/renew', + auth.tokenTrade(auth.PUBKEY, auth.PRIKEY, userFunction), +); app.get('/auth/Token/proto', auth.firstSetupUserSignupExists()); -// TODO way to populate this semi-automatically? -var HANDLERS = { - "loginHandler": function() { +/** + * Routes to operate on the roles service. + * + * Used to display the current configuration of the roles service + * and also update the configuration of the roles service. + */ + +app.use('/api/roles', roleRoutes); + +/** + * Linking all handlers to bind to the application at runtime + * + * @todo : populate these semi-automatically + */ +const HANDLERS = { + monitorCheck: monitor.check, + mongoFind: dataHandlers.General.find, + mongoAdd: dataHandlers.General.add, + mongoUpdate: dataHandlers.General.update, + mongoDelete: dataHandlers.General.delete, + mongoDistinct: dataHandlers.General.distinct, + filterHandler: auth.filterHandler, + editHandler: auth.editHandler, + getDataset: DataSet.getDataset, + trainModel: Model.trainModel, + deleteDataset: DataSet.deleteData, + sendTrainedModel: Model.sendTrainedModel, + proxyHandler, + loginHandler: function () { return auth.loginHandler(auth.PUBKEY); }, - "sanitizeBody": function() { + sanitizeBody: function () { return sanitizeBody; }, - "monitorCheck": monitor.check, - "mongoFind": dataHandlers.General.find, - "mongoAdd": dataHandlers.General.add, - "mongoUpdate": dataHandlers.General.update, - "mongoDelete": dataHandlers.General.delete, - "mongoDistinct": dataHandlers.General.distinct, - "filterHandler": auth.filterHandler, - "permissionHandler": permissionHandler, - "editHandler": auth.editHandler, - "proxyHandler": proxyHandler, - "getDataset": DataSet.getDataset, - "trainModel": Model.trainModel, - "deleteDataset": DataSet.deleteData, - "sendTrainedModel": Model.sendTrainedModel, - "iipHandler": function() { + iipHandler: function () { return iipHandler; }, - "markMulti": function() { + markMulti: function () { return dataHandlers.Mark.multi; }, - "markSpatial": function() { + markSpatial: function () { return dataHandlers.Mark.spatial; }, - "findMarkTypes": function() { + findMarkTypes: function () { return dataHandlers.Mark.findMarkTypes; }, - "heatmapTypes": function() { + heatmapTypes: function () { return dataHandlers.Heatmap.types; }, - "wcido": function() { + wcido: function () { return dataHandlers.User.wcido; }, - "addPresetlabels": function() { + addPresetlabels: function () { return dataHandlers.Presetlabels.add; }, - "updatePresetlabels": function() { + updatePresetlabels: function () { return dataHandlers.Presetlabels.update; }, - "removePresetlabels": function() { + removePresetlabels: function () { return dataHandlers.Presetlabels.remove; }, }; -// register configurable services -// TODO verify all -for (let i in routeConfig) { - if (Object.prototype.hasOwnProperty.call(routeConfig, i)) { - let rule = routeConfig[i]; - if (!rule.method) { - console.error('rule number '+ i +' has no "method"'); - process.exit(1); - } - if (rule.method == 'static') { - if (!rule.use) { - console.error('rule number '+ i +' is static and has no "use"'); - process.exit(1); +/** + * Bind routes.json configuration to application at rumtime. + * + * there is no need to check for validity of routes.json during runtine because + * a dedicated service is written to validate and test the route configurations. + * + * It is run at built time (of container) and therefore addiitonal checks to ensure + * that all required fields are specified are no longer needed. + */ +Object.keys(routeConfig).forEach((index) => { + const rule = routeConfig[index]; + + /** to add directory as a static location to be directly served */ + if (rule.method === 'static') { + app.use(express.static(rule.use)); + return; + } + + /** destruct access specifier data from route entry */ + const { entity, operation } = rule.access; + + /** to link a function / middleware to the application */ + app[rule.method](rule.route, RoleProcessor(entity, operation)); + + Object.keys(rule.handlers).forEach((handlerIndex) => { + if (Object.prototype.hasOwnProperty.call(rule.handlers, handlerIndex)) { + const handler = rule.handlers[handlerIndex]; + const args = handler.args || []; + + if (typeof HANDLERS[handler.function] !== 'function') { + console.error(handler); } - app.use(express.static(rule.use)); + + /** register a route with handler and arguments dynamically */ + app[rule.method](rule.route, HANDLERS[handler.function](...args)); } else { - for (let j in rule.handlers) { - if (Object.prototype.hasOwnProperty.call(rule.handlers, j)) { - let handler = rule.handlers[j]; - if (!rule.route) { - console.error('rule number '+ i +' has no "route"'); - process.exit(1); - } - if (!handler.function) { - console.error('rule number '+ i +' handler ' + j + ' has no "function"'); - process.exit(1); - } - if (! HANDLERS.hasOwnProperty(handler.function)) { - console.error('handler named "'+ handler.function + '" not found (rule '+ i +' handler ' + j + ')'); - process.exit(1); - } - let args = handler.args || []; - // handler.function needs to be in handlers - app[rule.method](rule.route, HANDLERS[handler.function](...args)); - } - } + console.error(handlerIndex); } - } -} + }); +}); -// render mongo returns/data -app.use('/data', function(req, res, next) { +/** route to test data exchange */ +app.use('/data', (req, res) => { if (!req.data) { - res.status(404).json({}); + return res.status(404).json({}); } - res.json(req.data); + return res.json(req.data); }); -// error handler -app.use(function(err, req, res, next) { - let statusCode = err.statusCode || 500; - // wrap strings in a json - if (typeof err === 'string' || err instanceof String) { - err = {'error': err}; - console.error(err); - } else { - console.error(err.error || err.message || err.toString()); +/** sending error response if application fails */ +app.use((err, req, res, next) => { + const statusCode = err.statusCode || 500; + console.error(`Last layer reached, code ${statusCode}`); + let errorResponse = err; + + if (typeof err === 'string') { + errorResponse = { error: err }; + console.log(`error : ${errorResponse}`); + return res.status(statusCode).json(errorResponse); } - res.status(statusCode).json(err); + + console.error(err.error || err.message || err.toString()); + return res.status(statusCode).json({ err, code: statusCode }); }); -var startApp = function(app) { - return function() { - // Prepare for SSL/HTTPS - var httpsOptions = {}; - try { - var sslPkPath = "./ssl/privatekey.pem"; - var sslCertPath = "./ssl/certificate.pem"; - if (fs.existsSync(sslPkPath) && fs.existsSync(sslCertPath)) { - console.info("Starting in HTTPS Mode mode"); - httpsOptions.key = fs.readFileSync(sslPkPath, 'utf8'); - httpsOptions.cert = fs.readFileSync(sslCertPath, 'utf8'); - } - } catch (err) { - console.error(err); - } - if (httpsOptions.key && httpsOptions.cert) { - https.createServer(httpsOptions, app).listen(PORT, () => console.log('listening HTTPS on ' + PORT)); - } else { - app.listen(PORT, () => console.log('listening on ' + PORT)); +/** + * export application to be consumed in two modules. + * - tests + * - server.js to launch a cluster + */ +module.exports = app; + +/** + * Bootstraps an application that is launched via throng / process manager + * @param {Application} app instance of express application + * @returns void + */ +const startApp = (application) => () => { + const httpsOptions = {}; + try { + const sslPkPath = sslPath.privateKey; + const sslCertPath = sslPkPath.publicKey; + + if (fs.existsSync(sslPkPath) && fs.existsSync(sslCertPath)) { + console.info('Starting in HTTPS Mode mode'); + httpsOptions.key = fs.readFileSync(sslPkPath, 'utf8'); + httpsOptions.cert = fs.readFileSync(sslCertPath, 'utf8'); } - }; + } catch (err) { + console.error('Error adding ssl certificates'); + console.error(err); + } + + /** if https ready, launch with ssl, else without */ + if (httpsOptions.key && httpsOptions.cert) { + https + .createServer(httpsOptions, application) + .listen(PORT, () => console.log(`listening HTTPS on ${PORT}`)); + } else { + application.listen(PORT, () => console.log(`listening HTTP on ${PORT}`)); + } }; +/** launch the application as multiple workers */ throng(WORKERS, startApp(app)); /** initialize DataTransformationHandler only after database is ready */ -connector.init().then(() => { - const handler = new DataTransformationHandler(MONGO_URI, './json/configuration.json'); - handler.startHandler(); -}).catch((e) => { - console.error("error connecting to database"); - process.exit(1); -}); +connector + .init() + .then(async () => { + const handler = new DataTransformationHandler( + MONGO_URI, + './json/configuration.json', + ); -module.exports = app; // for tests + /** initialize the roles service and start updation listener */ + await initializeRolesService(); + roleStatusCheck(); + handler.startHandler(); + }) + .catch((e) => { + console.error('error connecting to database'); + console.error(e); + process.exit(1); + }); diff --git a/draft.md b/draft.md new file mode 100644 index 0000000..1654ba2 --- /dev/null +++ b/draft.md @@ -0,0 +1,23 @@ +# Role-Based Access Control Staging Area + +**Note**: this pull request is not initiated to be merged, but to have a single point status check of the project progress. + + +## Summary +- since multiple developers are working on this repository during GSoC, and the scope of the projects are often intersecting, therefore merge conflicts are destined to arise. +- Ideally, this could have been resolved with Pull Request Stacking, but since Github does not provide this out of the box, it can become a bit troublesome. As any conflict in one PR will require manual fixes in the rest of the stack. +- Due to this, I believe that instead of creating PRs that'd require repeated merge-conflict fixes to track the progress, i'd push commits on this draft branch to track the program progress, and have one pull request open at a time for merging. + +## Changes +- [x] Linting and Styling + - [x] Remove existing non-working esllit config + - [x] Add fresh eslint config folllowing a pre-defined guide + - [x] Add a formatter (prettier) which is in sync with eslint + - [x] Configure tasks for linting + - [x] Lint and format existing codebasec +- [ ] Refactoring Handlers + - [ ] ...pending + + +## Todo +- add a structured list of components for visibility. \ No newline at end of file diff --git a/handlers/authHandlers.js b/handlers/authHandlers.js index c5c470f..9334cf1 100644 --- a/handlers/authHandlers.js +++ b/handlers/authHandlers.js @@ -1,127 +1,94 @@ -// handle auth services -var jwt = require('jsonwebtoken'); -const jwksClient = require('jwks-rsa'); -var atob = require('atob'); -var fs = require('fs'); -var filterFunction = require('./filterFunction.js'); +/** importing packages and modules */ +const atob = require('atob'); +const jwt = require('jsonwebtoken'); -const {execSync} = require('child_process'); -const preCommand = "openssl req -subj "; -const postCommand = " -x509 -nodes -newkey rsa:2048 -keyout ./keys/key -out ./keys/key.pub"; -var JWK_URL = process.env.JWK_URL; -var DISABLE_SEC = (process.env.DISABLE_SEC === 'true') || false; -var AUD = process.env.AUD || false; -var ISS = process.env.ISS || false; -var EXPIRY = process.env.EXPIRY || '1d'; -var DEFAULT_USER_TYPE = process.env.DEFAULT_USER_TYPE || 'Null'; -var PUBKEY; -var PRIKEY; -var CLIENT; -var GENERATE_KEY_IF_MISSING = (process.env.GENERATE_KEY_IF_MISSING === 'true') || false; -var ENABLE_SECURITY_AT = (process.env.ENABLE_SECURITY_AT ? process.env.ENABLE_SECURITY_AT : "") || false; +/** import local dependencies and services */ +const filterFunction = require('./filterFunction'); -if (!fs.existsSync('./keys/key') && !fs.existsSync('./keys/key.pub') && GENERATE_KEY_IF_MISSING) { - try { - execSync(`${preCommand}'/CN=www.camicroscope.com/O=caMicroscope Local Instance Key./C=US'${postCommand}`); - } catch (err) { - console.log({err: err}); - } -} +/** + * Loading services + * + * roles => to operate on roles and rights + * keys => to operate on keys and security + */ +const { DEFAULT_ROLE } = require('../service/roles/roles'); +const { + generateKeysIfMissing, + getJWKSClient, + readPrivateKey, + readPublicKey, + isSecurityDisabled, +} = require('../service/keys'); -try { - const prikeyPath = './keys/key'; - if (fs.existsSync(prikeyPath)) { - PRIKEY = fs.readFileSync(prikeyPath, 'utf8'); - } else { - if (DISABLE_SEC || ENABLE_SECURITY_AT && Date.parse(ENABLE_SECURITY_AT) > Date.now()) { - PRIKEY = ''; - console.warn('prikey null since DISABLE_SEC and no prikey provided'); - } else { - console.error('prikey does not exist'); - } - } -} catch (err) { - console.error(err); -} +/** + * Loading environment variables. for details about configurations, check .env.config + * + * AUD : the audience accepted by the service + * ISS : the issuer of the token + * EXPIRY : timestamp when jwks expires, default = 1d + */ +const { AUD, ISS, EXPIRY } = process.env; -try { - const pubkeyPath = './keys/key.pub'; - if (fs.existsSync(pubkeyPath)) { - var PUBKEY = fs.readFileSync(pubkeyPath, 'utf8'); - } else { - if (DISABLE_SEC || ENABLE_SECURITY_AT && Date.parse(ENABLE_SECURITY_AT) > Date.now()) { - PUBKEY = ''; - console.warn('pubkey null since DISABLE_SEC and no pubkey provided'); - } else { - console.error('pubkey does not exist'); - } - } -} catch (err) { - console.error(err); -} +/** + * generate the keys if they are missing from /keys directory + */ +generateKeysIfMissing(); -if (DISABLE_SEC && !JWK_URL) { - CLIENT = jwksClient({ - jwksUri: 'https://www.googleapis.com/oauth2/v3/certs', // a default value - }); -} else if (JWK_URL) { - CLIENT = jwksClient({ - jwksUri: JWK_URL, - }); -} else { - console.error('need JWKS URL (JWK_URL)'); - process.exit(1); -} +/** + * Read public and private keys from local fs, giving due respect to security configurations. + */ +const keys = { + private: readPrivateKey(), + public: readPublicKey(), +}; + +/** + provides a JWKS client based on configurations which can be directly exported from the auth handler + */ +const CLIENT = getJWKSClient(); -const getToken = function(req) { - if (req.headers.authorization && - req.headers.authorization.split(' ')[0] === 'Bearer') { // Authorization: Bearer g1jipjgi1ifjioj - // Handle token presented as a Bearer token in the Authorization header +/** + * Returns the token parsed either from the authorization header, the query param, or a cookie + * @param {Request} req incoming http request + * @returns {string} token + */ +const getToken = (req) => { + /** Authorization: Bearer tokenHere */ + if ( + req.headers.authorization && + req.headers.authorization.split(' ')[0] === 'Bearer' + ) { return req.headers.authorization.split(' ')[1]; - } else if (req.query && req.query.token) { - // Handle token presented as URI param + } + + /** Token from query param */ + if (req.query && req.query.token) { return req.query.token; - } else if (req.cookies && req.cookies.token) { - // Handle token presented as a cookie parameter + } + + /** Token as a cookie */ + if (req.cookies && req.cookies.token) { return req.cookies.token; } }; function getJwtKid(token) { - var base64Url = token.split('.')[0]; - var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); - var jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) { - return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); - }).join('')); + const base64Url = token.split('.')[0]; + const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); + const jsonPayload = decodeURIComponent( + atob(base64) + .split('') + .map((c) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`) + .join(''), + ); return JSON.parse(jsonPayload).kid; -}; - -function jwkTokenTrade(jwksClient, signKey, userFunction) { - return function(req, res) { - var THISTOKEN = getToken(req); - if (!THISTOKEN) { - res.status(401).send('{"err":"no token found"}'); - } - jwksClient.getSigningKey(getJwtKid(THISTOKEN), (err, key) => { - // console.log(key); - if (err) { - console.error(err); - res.status(401).send({ - 'err': err, - }); - } else { - const useKey = key.publicKey || key.rsaPublicKey; - tokenTrade(useKey, signKey, userFunction)(req, res); - } - }); - }; } // curry these calls function tokenTrade(checkKey, signKey, userFunction) { - return function(req, res) { - var THISTOKEN = getToken(req); + return function middleware(req, res) { + const THISTOKEN = getToken(req); const jwtOptions = {}; if (AUD) { jwtOptions.audience = AUD; @@ -129,50 +96,76 @@ function tokenTrade(checkKey, signKey, userFunction) { if (ISS) { jwtOptions.issuer = ISS; } - jwt.verify(THISTOKEN, checkKey, jwtOptions, function(err, token) { + jwt.verify(THISTOKEN, checkKey, jwtOptions, (err, token) => { if (err) { console.error(err); - res.status(401).send({ - 'err': err, + return res.status(401).send({ err }); + } + + if (!(token && (token.email || token.sub))) { + // jwt doesn't say who you are, so bye + res.send(401).send({ + err: 'email and sub are unset from source token', }); } else { - if (!(token && (token.email || token.sub))) { - // jwt doesn't say who you are, so bye - res.send(401).send({ - err: 'email and sub are unset from source token', - }); - } else { - userFunction(token).then((x) => { + userFunction(token) + .then((x) => { // console.log(x); if (x === false) { res.status(401).send({ - 'err': 'User Unauthorized', + err: 'User Unauthorized', }); } else { - data = x; - delete data['exp']; + const data = x; + delete data.exp; // sign using the mounted key - var token = jwt.sign(data, signKey, { + const newToken = jwt.sign(data, signKey, { algorithm: 'RS256', expiresIn: EXPIRY, }); - res.send({ - 'token': token, - }); + res.send({ token: newToken }); } - }).catch((e) => { + }) + .catch((e) => { console.log(e); res.status(401).send(e); }); - } } }); }; } +function jwkTokenTrade(jwksClient, signKey, userFunction) { + return (req, res) => { + const token = getToken(req); + if (!token) { + return res.status(401).send('{"err":"no token found"}'); + } + + jwksClient.getSigningKey(getJwtKid(token), (err, key) => { + if (err) { + console.error(err); + return res.status(401).send({ + err, + }); + } + + const useKey = key.publicKey || key.rsaPublicKey; + tokenTrade(useKey, signKey, userFunction)(req, res); + }); + }; +} + +/** + * + * @param {string} checkKey + * @returns {Middleware} express middleware to process auth layer + */ function loginHandler(checkKey) { - return function(req, res, next) { - if (DISABLE_SEC || ENABLE_SECURITY_AT && Date.parse(ENABLE_SECURITY_AT) > Date.now()) { + /** return a middle */ + return (req, res, next) => { + /** if security enabled after a timestamp */ + if (isSecurityDisabled()) { let token = {}; try { token = jwt.decode(getToken(req)) || {}; @@ -180,7 +173,7 @@ function loginHandler(checkKey) { console.warn(e); } req.tokenInfo = token; - req.userType = token.userType || DEFAULT_USER_TYPE || 'Null'; + req.userType = token.userType || DEFAULT_ROLE; req.userFilter = token.userFilter || ['Public']; next(); } else { @@ -191,15 +184,15 @@ function loginHandler(checkKey) { if (ISS) { jwtOptions.issuer = ISS; } - jwt.verify(getToken(req), checkKey, jwtOptions, function(err, token) { + jwt.verify(getToken(req), checkKey, jwtOptions, (err, token) => { if (err) { console.error(err); res.status(401).send({ - 'err': err, + err, }); } else { req.tokenInfo = token; - req.userType = token.userType || DEFAULT_USER_TYPE || 'Null'; + req.userType = token.userType || DEFAULT_ROLE; req.userFilter = token.userFilter || ['Public']; next(); } @@ -210,38 +203,48 @@ function loginHandler(checkKey) { // use filter handler AFTER data handler function filterHandler(dataField, filterField, attrField) { - return function(req, res, next) { - req[dataField] = filterFunction(req[filterField], req[dataField], attrField, '**'); + return (req, res, next) => { + req[dataField] = filterFunction( + req[filterField], + req[dataField], + attrField, + '**', + ); next(); }; } // use edit handler AFTER a find route to populate data, but BEFORE the edit itself function editHandler(dataField, filterField, attrField) { - return function(req, res, next) { + return (req, res, next) => { if (filterField && attrField) { - req[dataField] = filterFunction(req[filterField], req[dataField], attrField, '**'); + req[dataField] = filterFunction( + req[filterField], + req[dataField], + attrField, + '**', + ); } if (!Array.isArray(req[dataField])) { req[dataField] = [req[dataField]]; } // edit routes should operate on one object - if (req[dataField].length == 1) { + if (req[dataField].length === 1) { // DESTROY query - for (let n in req.query) { + for (const n in req.query) { if (req.query.hasOwnProperty(n)) { delete req.query[n]; } } - req.query = {_id: req[dataField][0]._id['$oid']}; + req.query = { _id: req[dataField][0]._id.$oid }; next(); - } else if (req[dataField].length == 0) { - let errorMessage = {}; + } else if (req[dataField].length === 0) { + const errorMessage = {}; errorMessage.error = 'Nothing applicable to change.'; errorMessage.statusCode = 400; next(errorMessage); } else { - let errorMessage = {}; + const errorMessage = {}; errorMessage.error = 'At most one document may be changed at once.'; errorMessage.statusCode = 400; next(errorMessage); @@ -249,30 +252,30 @@ function editHandler(dataField, filterField, attrField) { }; } +/** return true or false based on whether security is enabled or not */ function firstSetupUserSignupExists() { - return function(req, res) { - if (ENABLE_SECURITY_AT && Date.parse(ENABLE_SECURITY_AT) > Date.now()) { + return (req, res) => { + if (isSecurityDisabled()) { res.send({ - 'exists': true, + exists: true, }); } else { res.send({ - 'exists': false, + exists: false, }); } }; } - -auth = {}; -auth.jwkTokenTrade = jwkTokenTrade; -auth.tokenTrade = tokenTrade; -auth.filterHandler = filterHandler; -auth.loginHandler = loginHandler; -auth.editHandler = editHandler; -auth.firstSetupUserSignupExists = firstSetupUserSignupExists; -auth.CLIENT = CLIENT; -auth.PRIKEY = PRIKEY; -auth.PUBKEY = PUBKEY; - -module.exports = auth; +/** export authHandler functions */ +module.exports = { + jwkTokenTrade, + tokenTrade, + filterHandler, + loginHandler, + editHandler, + firstSetupUserSignupExists, + CLIENT, + PRIKEY: keys.private, + PUBKEY: keys.public, +}; diff --git a/handlers/dataHandlers.js b/handlers/dataHandlers.js index b89b5af..a250022 100644 --- a/handlers/dataHandlers.js +++ b/handlers/dataHandlers.js @@ -1,10 +1,10 @@ const DISABLE_SEC = (process.env.DISABLE_SEC === 'true') || false; -const mongoDB = require("../service/database"); +const mongoDB = require('../service/database'); -var General = {}; -General.find = function(db, collection) { - return function(req, res, next) { - var query = req.query; +const General = {}; +General.find = function (db, collection) { + return function (req, res, next) { + const { query } = req; mongoDB.find(db, collection, query).then((x) => { req.data = x; next(); @@ -12,20 +12,20 @@ General.find = function(db, collection) { }; }; -General.get = function(db, collection) { - return function(req, res, next) { - var query = req.query; +General.get = function (db, collection) { + return function (req, res, next) { + const { query } = req; delete query.token; - mongoDB.find(db, collection, {_id: req.query.id}).then((x) => { + mongoDB.find(db, collection, { _id: req.query.id }).then((x) => { req.data = x; next(); }).catch((e) => next(e)); }; }; -General.distinct = function(db, collection, upon) { - return function(req, res, next) { - var query = req.query; +General.distinct = function (db, collection, upon) { + return function (req, res, next) { + const { query } = req; delete query.token; mongoDB.distinct(db, collection, upon, query).then((x) => { req.data = x; @@ -34,9 +34,9 @@ General.distinct = function(db, collection, upon) { }; }; -General.add = function(db, collection) { - return function(req, res, next) { - var data = JSON.parse(req.body); +General.add = function (db, collection) { + return function (req, res, next) { + const data = JSON.parse(req.body); mongoDB.add(db, collection, data).then((x) => { req.data = x; next(); @@ -44,11 +44,11 @@ General.add = function(db, collection) { }; }; -General.update = function(db, collection) { - return function(req, res, next) { - var query = req.query; +General.update = function (db, collection) { + return function (req, res, next) { + const { query } = req; delete query.token; - var newVals = { + const newVals = { $set: JSON.parse(req.body), }; mongoDB.update(db, collection, query, newVals).then((x) => { @@ -58,9 +58,9 @@ General.update = function(db, collection) { }; }; -General.delete = function(db, collection) { - return function(req, res, next) { - var query = req.query; +General.delete = function (db, collection) { + return function (req, res, next) { + const { query } = req; delete query.token; mongoDB.delete(db, collection, query).then((x) => { req.data = x; @@ -69,26 +69,26 @@ General.delete = function(db, collection) { }; }; -var Presetlabels = {}; +const Presetlabels = {}; // add a label -Presetlabels.add = function(req, res, next) { - var query = req.query; +Presetlabels.add = function (req, res, next) { + const { query } = req; delete query.token; - var labels = JSON.parse(req.body); - mongoDB.update('camic', 'configuration', {'config_name': 'preset_label'}, {$push: {configuration: labels}}).then((x) => { + const labels = JSON.parse(req.body); + mongoDB.update('camic', 'configuration', { config_name: 'preset_label' }, { $push: { configuration: labels } }).then((x) => { req.data = x; next(); }).catch((e) => next(e)); }; // update a label -Presetlabels.update = function(req, res, next) { - var query = req.query; +Presetlabels.update = function (req, res, next) { + const { query } = req; delete query.token; - var labels = JSON.parse(req.body); + const labels = JSON.parse(req.body); // initial data - var newVals = { + const newVals = { $set: { 'configuration.$.id': labels.id, 'configuration.$.type': labels.type, @@ -99,68 +99,68 @@ Presetlabels.update = function(req, res, next) { // $unset/$set size if (labels.size) { - newVals['$set']['configuration.$.size'] = labels.size; + newVals.$set['configuration.$.size'] = labels.size; } else { - if (!newVals['$unset']) newVals['$unset'] = {}; - newVals['$unset']['configuration.$.size'] = 1; + if (!newVals.$unset) newVals.$unset = {}; + newVals.$unset['configuration.$.size'] = 1; } // $unset/$set key if (labels.key) { - newVals['$set']['configuration.$.key'] = labels.key; + newVals.$set['configuration.$.key'] = labels.key; } else { - if (!newVals['$unset']) newVals['$unset'] = {}; - newVals['$unset']['configuration.$.key'] = 1; + if (!newVals.$unset) newVals.$unset = {}; + newVals.$unset['configuration.$.key'] = 1; } mongoDB.update('camic', 'configuration', - { - 'config_name': 'preset_label', - 'configuration.id': query.id, - }, newVals).then((x) => { + { + config_name: 'preset_label', + 'configuration.id': query.id, + }, newVals).then((x) => { req.data = x; next(); }).catch((e) => next(e)); }; // remove a label by key -Presetlabels.remove = function(req, res, next) { - var query = req.query; +Presetlabels.remove = function (req, res, next) { + const { query } = req; delete query.token; mongoDB.update('camic', 'configuration', - { - 'config_name': 'preset_label', - }, {$pull: {configuration: {id: query.id}}}).then((x) => { + { + config_name: 'preset_label', + }, { $pull: { configuration: { id: query.id } } }).then((x) => { req.data = x; next(); }).catch((e) => next(e)); }; -var Mark = {}; +const Mark = {}; // special routes -Mark.spatial = function(req, res, next) { - var query = req.query; +Mark.spatial = function (req, res, next) { + const { query } = req; delete query.token; // handle x0, y0, x1, y1, footprint if (req.query.x0 && req.query.x1) { query.x = { - '$gt': parseFloat(req.query.x0), - '$lt': parseFloat(req.query.x1), + $gt: parseFloat(req.query.x0), + $lt: parseFloat(req.query.x1), }; } delete query.x0; delete query.x1; if (req.query.y0 && req.query.y1) { query.y = { - '$gt': parseFloat(req.query.y0), - '$lt': parseFloat(req.query.y1), + $gt: parseFloat(req.query.y0), + $lt: parseFloat(req.query.y1), }; } delete query.y0; delete query.y1; if (query.footprint) { query.footprint = { - '$gt': parseFloat(query.footprint), + $gt: parseFloat(query.footprint), }; } mongoDB.find('camic', 'mark', query).then((x) => { @@ -169,10 +169,10 @@ Mark.spatial = function(req, res, next) { }).catch((e) => next(e)); }; -Mark.multi = function(req, res, next) { - var query = {}; +Mark.multi = function (req, res, next) { + const query = {}; - var postQuery = JSON.parse(req.body); + const postQuery = JSON.parse(req.body); // handle source if (postQuery.source) { @@ -185,27 +185,27 @@ Mark.multi = function(req, res, next) { } if (postQuery.ids) { - query['provenance.analysis.execution_id'] = {'$in': postQuery.ids}; + query['provenance.analysis.execution_id'] = { $in: postQuery.ids }; } // handle x0, y0, x1, y1, footprint if (postQuery.x0 && postQuery.x1) { query.x = { - '$gt': parseFloat(postQuery.x0), - '$lt': parseFloat(postQuery.x1), + $gt: parseFloat(postQuery.x0), + $lt: parseFloat(postQuery.x1), }; } if (postQuery.y0 && postQuery.y1) { query.y = { - '$gt': parseFloat(postQuery.y0), - '$lt': parseFloat(postQuery.y1), + $gt: parseFloat(postQuery.y0), + $lt: parseFloat(postQuery.y1), }; } if (postQuery.footprint) { query.footprint = { - '$gt': parseFloat(postQuery.footprint), + $gt: parseFloat(postQuery.footprint), }; } @@ -215,8 +215,8 @@ Mark.multi = function(req, res, next) { }).catch((e) => next(e)); }; -Mark.findMarkTypes = function(req, res, next) { - var query = req.query; +Mark.findMarkTypes = function (req, res, next) { + const { query } = req; if (query.slide) { query['provenance.image.slide'] = query.slide; delete query.slide; @@ -230,13 +230,13 @@ Mark.findMarkTypes = function(req, res, next) { if (query['provenance.analysis.source'] == 'human') { const pipeline = [ { - "$match": query, + $match: query, }, { - "$group": { - "_id": { - "creator": "$creator", - "analysis": "$provenance.analysis", - "shape": "$geometries.features.geometry.type", + $group: { + _id: { + creator: '$creator', + analysis: '$provenance.analysis', + shape: '$geometries.features.geometry.type', }, }, }, @@ -253,55 +253,55 @@ Mark.findMarkTypes = function(req, res, next) { } }; -var Heatmap = {}; -Heatmap.types = function(req, res, next) { - var query = req.query; +const Heatmap = {}; +Heatmap.types = function (req, res, next) { + const { query } = req; delete query.token; mongoDB.find('camic', 'heatmap', query, { - 'data': 0, + data: 0, }).then((x) => { - x.forEach((x)=>delete x.data); + x.forEach((x) => delete x.data); req.data = x; next(); }).catch((e) => next(e)); }; -var User = {}; +const User = {}; -User.forLogin = function(email) { - return mongoDB.find('camic', 'user', {'email': email}); +User.forLogin = function (email) { + return mongoDB.find('camic', 'user', { email }); }; -User.wcido = function(req, res, next) { - var userType = req.query.ut; - var permissions = { - slide: {post: true, delete: true, update: true}, - heatmap: {post: true, delete: true, update: true}, - heatmapEdit: {post: true, delete: true, update: true}, - user: {post: true, delete: true, update: true}, - config: {post: true, delete: true, update: true}, - mark: {post: true, delete: true, update: true}, - template: {post: true, delete: true, update: true}, - logs: {post: true, delete: true, update: true}, +User.wcido = function (req, res, next) { + const userType = req.query.ut; + const permissions = { + slide: { post: true, delete: true, update: true }, + heatmap: { post: true, delete: true, update: true }, + heatmapEdit: { post: true, delete: true, update: true }, + user: { post: true, delete: true, update: true }, + config: { post: true, delete: true, update: true }, + mark: { post: true, delete: true, update: true }, + template: { post: true, delete: true, update: true }, + logs: { post: true, delete: true, update: true }, }; if (DISABLE_SEC || userType == 'Admin') { res.send(permissions); } else if (userType == 'Editor') { - permissions['user'] = {post: false, delete: false, update: false}; - permissions['slide'] = {post: true, delete: false, update: true}; + permissions.user = { post: false, delete: false, update: false }; + permissions.slide = { post: true, delete: false, update: true }; res.send(permissions); } else if (userType == 'Null') { for (const key in permissions) { if (permissions.hasOwnProperty(key)) { - permissions[key] = {post: false, delete: false, update: false}; + permissions[key] = { post: false, delete: false, update: false }; if (key == 'logs') { - permissions[key] = {post: true, delete: false, update: false}; + permissions[key] = { post: true, delete: false, update: false }; } } } res.send(permissions); } else { - var error = {error: 'undefined UserType'}; + const error = { error: 'undefined UserType' }; res.send(error); } }; diff --git a/handlers/dataTransformationHandler.js b/handlers/dataTransformationHandler.js index 7f09a07..1a66560 100644 --- a/handlers/dataTransformationHandler.js +++ b/handlers/dataTransformationHandler.js @@ -1,5 +1,5 @@ -const fs = require("fs"); -const mongoDB = require("../service/database"); +const fs = require('fs'); +const mongoDB = require('../service/database'); class DataTransformationHandler { constructor(url, path) { @@ -14,7 +14,7 @@ class DataTransformationHandler { } startHandler() { - console.log("||-- Start --||"); + console.log('||-- Start --||'); this.counter = 0; this.max = 300; this.id = 1; @@ -28,7 +28,7 @@ class DataTransformationHandler { rawdata = fs.readFileSync(this.filePath); config = JSON.parse(rawdata); } catch (err) { - if (err.code == "ENOENT") { + if (err.code == 'ENOENT') { console.log(`'${this.filePath}' File Fot Found!`); } else { throw err; @@ -47,19 +47,19 @@ class DataTransformationHandler { } this.isProcessing = true; - const query = {config_name: "preset_label"}; + const query = { config_name: 'preset_label' }; try { /** fetch saved configurations */ - const rs = await mongoDB.find("camic", "configuration", query, false); + const rs = await mongoDB.find('camic', 'configuration', query, false); /** read default data and write to database */ if (rs.length < 1) { const defaultData = this.loadDefaultData(); - await mongoDB.add("camic", "configuration", defaultData); + await mongoDB.add('camic', 'configuration', defaultData); } /** if not default configuration */ - if (rs.length > 0 && rs[0].version != "1.0.0") { + if (rs.length > 0 && rs[0].version != '1.0.0') { const config = rs[0]; const list = []; if (config.configuration && Array.isArray(config.configuration)) { @@ -69,19 +69,19 @@ class DataTransformationHandler { } config.configuration = list; - config.version = "1.0.0"; + config.version = '1.0.0'; if (!(list && list.length)) { return; } /** delete old stored object and insert new one */ - await mongoDB.delete("camic", "configuration", query); - await mongoDB.add("camic", "configuration", config); + await mongoDB.delete('camic', 'configuration', query); + await mongoDB.add('camic', 'configuration', config); this.isProcessing = false; this.cleanHandler(); } } catch (err) { - console.log(`||-- The 'Preset Labels' Document Upgrade Is Failed --||`); + console.log('||-- The \'Preset Labels\' Document Upgrade Is Failed --||'); console.log(err); this.cleanHandler(); } @@ -94,17 +94,17 @@ class DataTransformationHandler { }); } if ( - node.data && - (typeof node.data === "object" || typeof node.data === "function") && - node.data !== null + node.data + && (typeof node.data === 'object' || typeof node.data === 'function') + && node.data !== null ) { const id = zeroFill(this.id++, this.idLength); - list.push({id, ...node.data}); + list.push({ id, ...node.data }); } } cleanHandler() { - console.log("||-- Done --||"); + console.log('||-- Done --||'); this.counter = 0; this.max = 300; this.id = 1; @@ -116,9 +116,9 @@ class DataTransformationHandler { function zeroFill(number, width) { width -= number.toString().length; if (width > 0) { - return new Array(width + (/\./.test(number) ? 2 : 1)).join("0") + number; + return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number; } - return number + ""; + return `${number}`; } module.exports = DataTransformationHandler; diff --git a/handlers/datasetHandler.js b/handlers/datasetHandler.js index 726332e..c799657 100644 --- a/handlers/datasetHandler.js +++ b/handlers/datasetHandler.js @@ -6,14 +6,13 @@ const tf = require('@tensorflow/tfjs-node'); const fs = require('fs'); const inkjet = require('inkjet'); -const crypto = require("crypto"); +const crypto = require('crypto'); const AdmZip = require('adm-zip'); const path = require('path'); let LABELS_PATH = null; let IMAGES_SPRITE_PATH = null; - class Data { constructor() { this.IMAGE_SIZE = null; @@ -29,20 +28,19 @@ class Data { this.xs = null; this.labels = null; } + async load() { - let This = this; + const This = this; const imgRequest = new Promise((resolve) => { // console.log(this.IMAGES_SPRITE_PATH); - inkjet.decode(fs.readFileSync(this.IMAGES_SPRITE_PATH), function(err, decoded) { - const pixels = Float32Array.from(decoded.data).map((pixel) => { - return pixel / 255; - }); + inkjet.decode(fs.readFileSync(this.IMAGES_SPRITE_PATH), (err, decoded) => { + const pixels = Float32Array.from(decoded.data).map((pixel) => pixel / 255); This.datasetImages = pixels; resolve(); }); }); - let labelsRequest = fs.readFileSync(this.LABELS_PATH); + const labelsRequest = fs.readFileSync(this.LABELS_PATH); const [imgResponse, labelsResponse] = await Promise.all([ imgRequest, labelsRequest, @@ -57,58 +55,56 @@ class Data { // Slice the the images and labels into train and test sets. this.trainImages = this.datasetImages.slice( - 0, - this.IMAGE_SIZE * this.NUM_TRAIN_ELEMENTS * this.NUM_CHANNELS, + 0, + this.IMAGE_SIZE * this.NUM_TRAIN_ELEMENTS * this.NUM_CHANNELS, ); this.testImages = this.datasetImages.slice( - this.IMAGE_SIZE * this.NUM_TRAIN_ELEMENTS * this.NUM_CHANNELS, + this.IMAGE_SIZE * this.NUM_TRAIN_ELEMENTS * this.NUM_CHANNELS, ); this.trainLabels = this.datasetLabels.slice( - 0, - this.NUM_CLASSES * this.NUM_TRAIN_ELEMENTS, + 0, + this.NUM_CLASSES * this.NUM_TRAIN_ELEMENTS, ); this.testLabels = this.datasetLabels.slice( - this.NUM_CLASSES * this.NUM_TRAIN_ELEMENTS, + this.NUM_CLASSES * this.NUM_TRAIN_ELEMENTS, ); } nextTrainBatch(batchSize) { return this.nextBatch( - batchSize, - [this.trainImages, this.trainLabels], - () => { - this.shuffledTrainIndex = - (this.shuffledTrainIndex + 1) % this.trainIndices.length; - return this.trainIndices[this.shuffledTrainIndex]; - }, + batchSize, + [this.trainImages, this.trainLabels], + () => { + this.shuffledTrainIndex = (this.shuffledTrainIndex + 1) % this.trainIndices.length; + return this.trainIndices[this.shuffledTrainIndex]; + }, ); } nextTestBatch(batchSize) { return this.nextBatch(batchSize, [this.testImages, this.testLabels], () => { - this.shuffledTestIndex = - (this.shuffledTestIndex + 1) % this.testIndices.length; + this.shuffledTestIndex = (this.shuffledTestIndex + 1) % this.testIndices.length; return this.testIndices[this.shuffledTestIndex]; }); } nextBatch(batchSize, data, index) { const batchImagesArray = new Float32Array( - batchSize * this.IMAGE_SIZE * this.NUM_CHANNELS, + batchSize * this.IMAGE_SIZE * this.NUM_CHANNELS, ); const batchLabelsArray = new Uint8Array(batchSize * this.NUM_CLASSES); for (let i = 0; i < batchSize; i++) { const idx = index(); const image = data[0].slice( - idx * this.IMAGE_SIZE * this.NUM_CHANNELS, - idx * this.IMAGE_SIZE * this.NUM_CHANNELS + this.IMAGE_SIZE * this.NUM_CHANNELS, + idx * this.IMAGE_SIZE * this.NUM_CHANNELS, + idx * this.IMAGE_SIZE * this.NUM_CHANNELS + this.IMAGE_SIZE * this.NUM_CHANNELS, ); batchImagesArray.set(image, i * this.IMAGE_SIZE * this.NUM_CHANNELS); const label = data[1].slice( - idx * this.NUM_CLASSES, - idx * this.NUM_CLASSES + this.NUM_CLASSES, + idx * this.NUM_CLASSES, + idx * this.NUM_CLASSES + this.NUM_CLASSES, ); batchLabelsArray.set(label, i * this.NUM_CLASSES); } @@ -119,46 +115,45 @@ class Data { this.NUM_CHANNELS, ]); this.labels = tf.tensor2d(batchLabelsArray, [batchSize, this.NUM_CLASSES]).toFloat(); - return {xs: this.xs, labels: this.labels}; + return { xs: this.xs, labels: this.labels }; } } function getDataset() { - return function(req, res) { - let data = JSON.parse(req.body); + return function (req, res) { + const data = JSON.parse(req.body); // console.log(req.body.ar); - let userFolder = crypto.randomBytes(20).toString('hex'); + const userFolder = crypto.randomBytes(20).toString('hex'); if (!fs.existsSync('dataset')) { fs.mkdirSync('dataset/'); } - fs.mkdirSync('dataset/' + userFolder); - fs.writeFile('dataset/' + userFolder + '/dataset.zip', data.file, - {encoding: 'base64'}, - async function(err) { - let zip = new AdmZip('dataset/' + userFolder + '/dataset.zip'); - await zip.extractAllTo('dataset/' + userFolder, true); - LABELS_PATH = 'dataset/' + userFolder + '/labels.bin'; - IMAGES_SPRITE_PATH = 'dataset/' + userFolder + '/data.jpg'; - fs.unlink('dataset/' + userFolder + '/dataset.zip', () => {}); - res.json({status: 'DONE', userFolder: userFolder}); - }, - ); + fs.mkdirSync(`dataset/${userFolder}`); + fs.writeFile(`dataset/${userFolder}/dataset.zip`, data.file, + { encoding: 'base64' }, + async (err) => { + const zip = new AdmZip(`dataset/${userFolder}/dataset.zip`); + await zip.extractAllTo(`dataset/${userFolder}`, true); + LABELS_PATH = `dataset/${userFolder}/labels.bin`; + IMAGES_SPRITE_PATH = `dataset/${userFolder}/data.jpg`; + fs.unlink(`dataset/${userFolder}/dataset.zip`, () => {}); + res.json({ status: 'DONE', userFolder }); + }); }; } function deleteData() { - return function(req, res) { - let data = JSON.parse(req.body); + return function (req, res) { + const data = JSON.parse(req.body); let dir = path.normalize(data.userFolder).replace(/^(\.\.(\/|\\|$))+/, ''); dir = path.join('./dataset/', dir); - fs.rmdir(dir, {recursive: true}, (err) => { + fs.rmdir(dir, { recursive: true }, (err) => { if (err) { throw err; } - console.log(`Temp folder deleted!`); + console.log('Temp folder deleted!'); }); - res.json({status: 'Temp folder deleted!'}); + res.json({ status: 'Temp folder deleted!' }); }; } -module.exports = {Data: Data, getDataset: getDataset, deleteData: deleteData}; +module.exports = { Data, getDataset, deleteData }; diff --git a/handlers/filterFunction.js b/handlers/filterFunction.js index 3f2912c..b38ab47 100644 --- a/handlers/filterFunction.js +++ b/handlers/filterFunction.js @@ -1,9 +1,9 @@ function filterFunction(filter, data, attr, wildcard) { - if (typeof filter==="string") { + if (typeof filter === 'string') { try { filter = JSON.parse(filter.replace(/'/g, '"')); } catch (err) { - filter=[filter]; // make an array of the filter + filter = [filter]; // make an array of the filter } } if (filter.indexOf(wildcard) == -1) { @@ -16,37 +16,32 @@ function filterFunction(filter, data, attr, wildcard) { return true; } try { - list=JSON.parse(x[attr].replace(/'/g, '"')); - return list.some((e) =>filter.indexOf(e) >= 0); + list = JSON.parse(x[attr].replace(/'/g, '"')); + return list.some((e) => filter.indexOf(e) >= 0); } catch (err) { // when list is not an array, but a string - list=x[attr]; + list = x[attr]; return filter.indexOf(x[attr]) >= 0; } }); + } else if (!data[attr]) { + data = data; } else { - if (!data[attr]) { - data = data; - } else { - let list; - try { - list=JSON.parse(data[attr].replace(/'/g, '"')); - if (list.some((e) => filter.indexOf(e) >= 0)) { - return data; - } else { - return {}; - } - } catch (err) { // when list is not an array, but a string - if (filter.indexOf(data[attr]) >= 0) { - return data; - } else { - return {}; - } + let list; + try { + list = JSON.parse(data[attr].replace(/'/g, '"')); + if (list.some((e) => filter.indexOf(e) >= 0)) { + return data; } + return {}; + } catch (err) { // when list is not an array, but a string + if (filter.indexOf(data[attr]) >= 0) { + return data; + } + return {}; } } } return data; } - module.exports = filterFunction; diff --git a/handlers/iipHandler.js b/handlers/iipHandler.js index d7cacd5..b6f7b63 100644 --- a/handlers/iipHandler.js +++ b/handlers/iipHandler.js @@ -1,8 +1,8 @@ -var proxy = require('http-proxy-middleware'); +const proxy = require('http-proxy-middleware'); -var IIP_PATH = process.env.IIP_PATH || 'http://ca-iip/'; +const IIP_PATH = process.env.IIP_PATH || 'http://ca-iip/'; -iipHandler = function(req, res, next) { +iipHandler = function (req, res, next) { if (req.query) { if (req.query.DeepZoom) { if (req.query.DeepZoom.endsWith('.dzi')) { @@ -28,12 +28,12 @@ iipHandler = function(req, res, next) { }, changeOrigin: true, target: IIP_PATH, - pathRewrite: function(path, req) { + pathRewrite(path, req) { // NOTE -- this may need to change if the original url has more subdirs or so added - var splitPath = path.split('/'); - return '/' + splitPath.slice(2, splitPath.length).join('/'); + const splitPath = path.split('/'); + return `/${splitPath.slice(2, splitPath.length).join('/')}`; }, - onProxyReq: function(proxyReq, req, res) { + onProxyReq(proxyReq, req, res) { if (req.method == 'POST') { proxyReq.write(req.body); proxyReq.end(); @@ -42,5 +42,4 @@ iipHandler = function(req, res, next) { })(req, res, next); }; - module.exports = iipHandler; diff --git a/handlers/modelTrainer.js b/handlers/modelTrainer.js index 123b8a2..b63cb00 100644 --- a/handlers/modelTrainer.js +++ b/handlers/modelTrainer.js @@ -4,8 +4,8 @@ const tf = require('@tensorflow/tfjs-node'); // proper nvidia drivers needs to be installed on both base machine and container for gpu training // const tf = require('@tensorflow/tfjs-node-gpu'); -const Data = require('./datasetHandler.js'); const AdmZip = require('adm-zip'); +const Data = require('./datasetHandler.js'); let Layers = []; let Params = {}; @@ -32,7 +32,7 @@ function getModel(Layers, Params, res) { }); } } catch (error) { - res.status(400).json({message: error.message}); + res.status(400).json({ message: error.message }); // res.send(error); } @@ -40,10 +40,10 @@ function getModel(Layers, Params, res) { } async function train(model, data, Params) { - let TRAIN_DATA_SIZE = Params.trainDataSize; - let TEST_DATA_SIZE = Params.testDataSize; - let WIDTH = Params.width; - let HEIGHT = Params.height; + const TRAIN_DATA_SIZE = Params.trainDataSize; + const TEST_DATA_SIZE = Params.testDataSize; + const WIDTH = Params.width; + const HEIGHT = Params.height; let d1; let d2; const [trainXs, trainYs] = tf.tidy(() => { d1 = data.nextTrainBatch(TRAIN_DATA_SIZE); @@ -91,22 +91,22 @@ async function run(Layers, Params, res, userFolder) { trained = await train(model, data, Params); console.log('TRAINING DONE'); - await model.save('file://./dataset/' + userFolder + '/'); + await model.save(`file://./dataset/${userFolder}/`); tf.dispose([model, trained, data.xs, data.labels]); tf.disposeVariables(); - let zip = new AdmZip(); - zip.addLocalFile('./dataset/' + userFolder + '/model.json'); - zip.addLocalFile('./dataset/' + userFolder + '/weights.bin'); - zip.writeZip('./dataset/' + userFolder + '/' + Params.modelName + '.zip'); + const zip = new AdmZip(); + zip.addLocalFile(`./dataset/${userFolder}/model.json`); + zip.addLocalFile(`./dataset/${userFolder}/weights.bin`); + zip.writeZip(`./dataset/${userFolder}/${Params.modelName}.zip`); - res.json({status: 'done'}); + res.json({ status: 'done' }); } catch (error) { console.log(error); tf.dispose([model, trained, data.xs, data.labels]); tf.disposeVariables(); - res.status(400).json({message: error.message}); + res.status(400).json({ message: error.message }); } } @@ -157,7 +157,7 @@ function makeLayers(layers, res, userFolder) { } } catch (error) { console.log(error); - res.status(400).json({message: error.message}); + res.status(400).json({ message: error.message }); return; } @@ -165,23 +165,21 @@ function makeLayers(layers, res, userFolder) { } function trainModel() { - return function(req, res) { - let data = JSON.parse(req.body); + return function (req, res) { + const data = JSON.parse(req.body); Params = data.Params; makeLayers(data.Layers, res, data.userFolder); }; } function sendTrainedModel() { - return function(req, res) { - let data = JSON.parse(req.body); - let downloadURL = '/workbench/download/' + data.userFolder; - let app = require('../caracal.js'); - app.get(downloadURL, (req1, res1) => - res1.download('./dataset/' + data.userFolder + '/' + data.Params.modelName + '.zip'), - ); - res.json({url: downloadURL}); + return function (req, res) { + const data = JSON.parse(req.body); + const downloadURL = `/workbench/download/${data.userFolder}`; + const app = require('../caracal.js'); + app.get(downloadURL, (req1, res1) => res1.download(`./dataset/${data.userFolder}/${data.Params.modelName}.zip`)); + res.json({ url: downloadURL }); }; } -module.exports = {trainModel: trainModel, sendTrainedModel: sendTrainedModel}; +module.exports = { trainModel, sendTrainedModel }; diff --git a/handlers/monitorHandlers.js b/handlers/monitorHandlers.js index 642b04a..067ac43 100644 --- a/handlers/monitorHandlers.js +++ b/handlers/monitorHandlers.js @@ -1,21 +1,21 @@ -const {getConnection} = require("../service/database/connector"); +const { getConnection } = require('../service/database/connector'); /** * @param {string} type Monitor to check status of database connection * @returns {Promise<{status:string, checkType:string}>} status of service */ -const check = function(type) { +const check = function (type) { return new Promise((resolve, reject) => { - if (type === "basic") { - resolve({status: "up", checkType: "basic"}); - } else if (type === "mongo") { + if (type === 'basic') { + resolve({ status: 'up', checkType: 'basic' }); + } else if (type === 'mongo') { if (getConnection() === undefined) { - const error = new Error("Error connecting to database"); + const error = new Error('Error connecting to database'); reject(error); } - resolve({status: "up", checkType: "mongo"}); + resolve({ status: 'up', checkType: 'mongo' }); } }); }; -module.exports = {check}; +module.exports = { check }; diff --git a/handlers/permssionHandler.js b/handlers/permssionHandler.js index 4462d06..43978b8 100644 --- a/handlers/permssionHandler.js +++ b/handlers/permssionHandler.js @@ -1,21 +1,42 @@ -var DISABLE_SEC = (process.env.DISABLE_SEC === 'true') || false; -var ENABLE_SECURITY_AT = (process.env.ENABLE_SECURITY_AT ? process.env.ENABLE_SECURITY_AT : "") || false; +/** + * @depreciated + * + * This is legacy code of the previous permissionHandler. + * This is no longer used, as all routes are checked for roles + */ -function permissionHandler(permissionList, test=false) { - return function(req, res, next) { - if (!test && DISABLE_SEC || ENABLE_SECURITY_AT && Date.parse(ENABLE_SECURITY_AT) > Date.now()) { +const { isSecurityDisabled } = require('../service/keys'); + +/** + * This is legacy code of the permission handler which is no longer used. This is being replaced by + * Role based access control that checks each and every route for roles defined in /services/roles. + * + * The roles service is responsible for assigning the roles to validated users, and declining access + * + * @deprecated + * @param {Array} permissionList Array of permissions that are allowed to access this route + * @param {bool} test setting test=true will bypass the role check + * @returns {Middleware} express middleware + */ +function permissionHandler(permissionList, test = false) { + return (req, res, next) => { + /** if security disabled, or testing mode enabled, then do not check for roles */ + if (isSecurityDisabled() || test) { + req.permission_ok = true; + next(); + } else if ( + req.tokenInfo.userType && + permissionList.indexOf(req.tokenInfo.userType) >= 0 + ) { + /** if user belongs to the correct role mapping */ req.permission_ok = true; next(); } else { - if (req.tokenInfo.userType && permissionList.indexOf(req.tokenInfo.userType) >= 0) { - req.permission_ok = true; - next(); - } else { - req.permission_ok = false; - let errorMessage = {'statusCode': 401}; - errorMessage.error = 'Permission not granted'; - next(errorMessage); - } + /** when user not allowed to move furhter */ + req.permission_ok = false; + const errorMessage = { statusCode: 401 }; + errorMessage.error = 'Permission not granted'; + next(errorMessage); } }; } diff --git a/handlers/proxyHandler.js b/handlers/proxyHandler.js index 22a5afa..92ddb09 100644 --- a/handlers/proxyHandler.js +++ b/handlers/proxyHandler.js @@ -1,8 +1,8 @@ -var proxy = require('http-proxy-middleware'); +const proxy = require('http-proxy-middleware'); -proxyHandler = function(target, n) { +proxyHandler = function (target, n) { n = n || 2; - return function(req, res, next) { + return function (req, res, next) { proxy({ secure: false, onError(err, req, res) { @@ -11,15 +11,15 @@ proxyHandler = function(target, n) { next(err); }, changeOrigin: true, - target: target, - pathRewrite: function(path, req) { + target, + pathRewrite(path, req) { console.log(target); console.log(path); // NOTE -- this may need to change if the original url has more subdirs or so added - var splitPath = path.split('/'); - return '/' + splitPath.slice(n, splitPath.length).join('/'); + const splitPath = path.split('/'); + return `/${splitPath.slice(n, splitPath.length).join('/')}`; }, - onProxyReq: function(proxyReq, req, res) { + onProxyReq(proxyReq, req, res) { if (req.method == 'POST') { proxyReq.write(req.body); proxyReq.end(); @@ -29,5 +29,4 @@ proxyHandler = function(target, n) { }; }; - module.exports = proxyHandler; diff --git a/handlers/sanitizeHandler.js b/handlers/sanitizeHandler.js index 575d07b..cd9e72d 100644 --- a/handlers/sanitizeHandler.js +++ b/handlers/sanitizeHandler.js @@ -1,18 +1,18 @@ -var ERR_ON_SANITIZE = (process.env.ERR_ON_SANITIZE === 'true') || false; +const ERR_ON_SANITIZE = (process.env.ERR_ON_SANITIZE === 'true') || false; function sanitizeBody(req, res, next) { // handle req body edgecases if (ERR_ON_SANITIZE) { - if (req.body.indexOf("<") >=0 || req.body.indexOf(">") >=0) { - let e = {'statusCode': 400}; + if (req.body.indexOf('<') >= 0 || req.body.indexOf('>') >= 0) { + const e = { statusCode: 400 }; e.error = 'Characters < and > disallowed in body.'; next(e); } else { next(); } } else { - req.body = req.body.replace(//g, ""); + req.body = req.body.replace(//g, ''); next(); } } diff --git a/handlers/userFunction.js b/handlers/userFunction.js index bd430d0..be134df 100644 --- a/handlers/userFunction.js +++ b/handlers/userFunction.js @@ -1,35 +1,46 @@ -var ALLOW_PUBLIC = (process.env.ALLOW_PUBLIC === 'true'); +const ALLOW_PUBLIC = process.env.ALLOW_PUBLIC === 'true'; -var dataHandlers = require('./dataHandlers.js'); -// userFunction -- used for login given id provider token +const dataHandlers = require('./dataHandlers.js'); + +/** + * Loading services + * + * roles => to operate on roles and summon default roles + */ +const { DEFAULT_ROLE } = require('../service/roles/roles'); + +/** + * Used for login + * @param {string} token JWT token in decoded format to read data about current user + * @returns Promise Express Middleware + */ function userFunction(token) { - return new Promise(function(res, rej) { - dataHandlers.User.forLogin(token.email).then((x)=>{ + return new Promise((resolve, reject) => { + dataHandlers.User.forLogin(token.email).then((x) => { if (x.length <= 0) { if (ALLOW_PUBLIC) { const publicToken = {}; publicToken.userFilter = ['Public']; - publicToken.userType = 'Null'; + publicToken.userType = DEFAULT_ROLE; publicToken.email = token.email; publicToken.name = token.name; publicToken.picture = token.picture; - res(publicToken); + resolve(publicToken); } else { - rej(new Error('Public users not allowed on this instance')); + reject(new Error('Public users not allowed on this instance')); } } else { const newToken = {}; - newToken.userType = x[0].userType || 'Null'; + newToken.userType = x[0].userType || DEFAULT_ROLE; newToken.userFilter = x[0].userFilter || ['Public']; newToken.sub = token.email; newToken.email = token.email; newToken.name = token.name; newToken.picture = token.picture; - res(newToken); + resolve(newToken); } }); }); } - module.exports = userFunction; diff --git a/old.routes.json b/old.routes.json new file mode 100644 index 0000000..bf308aa --- /dev/null +++ b/old.routes.json @@ -0,0 +1,466 @@ +[ + { + "method": "use", + "route": "/loader/", + "handlers": [ + { "function": "loginHandler", "args": [] }, + { "function": "permissionHandler", "args": [["Admin", "Editor"]] } + ] + }, + { + "method": "use", + "route": "/loader/slide/delete", + "handlers": [{ "function": "permissionHandler", "args": [["Admin"]] }] + }, + { + "method": "use", + "route": "/loader/", + "handlers": [ + { "function": "proxyHandler", "args": ["http://ca-load:4000/"] } + ] + }, + { + "method": "use", + "route": "/googleAuth/", + "handlers": [ + { "function": "proxyHandler", "args": ["http://ca-load:4001/"] } + ] + }, + + { + "method": "use", + "route": "/img/IIP/raw/", + "handlers": [ + { "function": "loginHandler", "args": [] }, + { "function": "iipHandler", "args": [] } + ] + }, + + { + "route": "/data", + "method": "use", + "handlers": [ + { "function": "loginHandler", "args": [] }, + { "function": "sanitizeBody", "args": [] } + ] + }, + + { + "route": "/data/Slide/find", + "method": "get", + "handlers": [ + { "function": "mongoFind", "args": ["camic", "slide"] }, + { "function": "filterHandler", "args": ["data", "userFilter", "filter"] } + ] + }, + { + "route": "/data/Slide/post", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoAdd", "args": ["camic", "slide"] } + ] + }, + { + "route": "/data/Slide/delete", + "method": "delete", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoFind", "args": ["camic", "slide"] }, + { "function": "editHandler", "args": ["data", "userFilter", "filter"] }, + { "function": "mongoDelete", "args": ["camic", "slide"] } + ] + }, + { + "route": "/data/Slide/update", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoFind", "args": ["camic", "slide"] }, + { "function": "editHandler", "args": ["data", "userFilter", "filter"] }, + { "function": "mongoUpdate", "args": ["camic", "slide"] } + ] + }, + + { + "route": "/data/Request/find", + "method": "get", + "handlers": [ + { "function": "permissionHandler", "args": [["Editor", "Admin"]] }, + { "function": "mongoFind", "args": ["camic", "request"] } + ] + }, + { + "route": "/data/Request/post", + "method": "post", + "handlers": [{ "function": "mongoAdd", "args": ["camic", "request"] }] + }, + { + "route": "/data/Request/delete", + "method": "delete", + "handlers": [ + { "function": "permissionHandler", "args": [["Editor", "Admin"]] }, + { "function": "mongoFind", "args": ["camic", "request"] }, + { "function": "editHandler", "args": ["data", "userFilter", "filter"] }, + { "function": "mongoDelete", "args": ["camic", "request"] } + ] + }, + + { + "route": "/data/Mark/find", + "method": "get", + "handlers": [{ "function": "mongoFind", "args": ["camic", "mark"] }] + }, + { + "route": "/data/Mark/post", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoAdd", "args": ["camic", "mark"] } + ] + }, + { + "route": "/data/Mark/delete", + "method": "delete", + "handlers": [ + { "function": "mongoFind", "args": ["camic", "mark"] }, + { "function": "editHandler", "args": ["data"] }, + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoDelete", "args": ["camic", "mark"] } + ] + }, + { + "route": "/data/Mark/update", + "method": "post", + "handlers": [ + { "function": "mongoFind", "args": ["camic", "mark"] }, + { "function": "editHandler", "args": ["data"] }, + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoUpdate", "args": ["camic", "mark"] } + ] + }, + { + "route": "/data/Mark/types", + "method": "get", + "handlers": [ + { + "function": "mongoDistinct", + "args": ["camic", "mark", "provenance.analysis"] + } + ] + }, + { + "route": "/data/Mark/multi", + "method": "post", + "handlers": [{ "function": "markMulti", "args": [] }] + }, + { + "route": "/data/Mark/spatial", + "method": "get", + "handlers": [{ "function": "markSpatial", "args": [] }] + }, + { + "route": "/data/Mark/findMarkTypes", + "method": "get", + "handlers": [{ "function": "findMarkTypes", "args": [] }] + }, + { + "route": "/data/Presetlabels/add", + "method": "post", + "handlers": [{ "function": "addPresetlabels", "args": [] }] + }, + { + "route": "/data/Presetlabels/update", + "method": "post", + "handlers": [{ "function": "updatePresetlabels", "args": [] }] + }, + { + "route": "/data/Presetlabels/remove", + "method": "post", + "handlers": [{ "function": "removePresetlabels", "args": [] }] + }, + { + "route": "/data/Template/find", + "method": "get", + "handlers": [{ "function": "mongoFind", "args": ["camic", "template"] }] + }, + { + "route": "/data/Template/post", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoAdd", "args": ["camic", "template"] } + ] + }, + { + "route": "/data/Template/delete", + "method": "delete", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoDelete", "args": ["camic", "template"] } + ] + }, + { + "route": "/data/Template/update", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin"]] }, + { "function": "mongoUpdate", "args": ["camic", "template"] } + ] + }, + + { + "route": "/data/Heatmap/find", + "method": "get", + "handlers": [{ "function": "mongoFind", "args": ["camic", "heatmap"] }] + }, + { + "route": "/data/Heatmap/types", + "method": "get", + "handlers": [{ "function": "heatmapTypes", "args": [] }] + }, + { + "route": "/data/Heatmap/post", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoAdd", "args": ["camic", "heatmap"] } + ] + }, + { + "route": "/data/Heatmap/delete", + "method": "delete", + "handlers": [ + { "function": "mongoFind", "args": ["camic", "heatmap"] }, + { "function": "editHandler", "args": ["data"] }, + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoDelete", "args": ["camic", "heatmap"] } + ] + }, + { + "route": "/data/Heatmap/update", + "method": "post", + "handlers": [ + { "function": "mongoFind", "args": ["camic", "heatmap"] }, + { "function": "editHandler", "args": ["data"] }, + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoUpdate", "args": ["camic", "heatmap"] } + ] + }, + + { + "route": "/data/HeatmapEdit/find", + "method": "get", + "handlers": [{ "function": "mongoFind", "args": ["camic", "heatmapEdit"] }] + }, + { + "route": "/data/HeatmapEdit/post", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoAdd", "args": ["camic", "heatmapEdit"] } + ] + }, + { + "route": "/data/HeatmapEdit/delete", + "method": "delete", + "handlers": [ + { "function": "mongoFind", "args": ["camic", "heatmap"] }, + { "function": "editHandler", "args": ["data"] }, + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoDelete", "args": ["camic", "heatmapEdit"] } + ] + }, + { + "route": "/data/HeatmapEdit/update", + "method": "post", + "handlers": [ + { "function": "mongoFind", "args": ["camic", "heatmap"] }, + { "function": "editHandler", "args": ["data"] }, + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoUpdate", "args": ["camic", "heatmapEdit"] } + ] + }, + + { + "route": "/data/Log/find", + "method": "get", + "handlers": [{ "function": "mongoFind", "args": ["camic", "log"] }] + }, + { + "route": "/data/Log/post", + "method": "post", + "handlers": [{ "function": "mongoAdd", "args": ["camic", "log"] }] + }, + { + "route": "/data/Log/delete", + "method": "delete", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoDelete", "args": ["camic", "log"] } + ] + }, + { + "route": "/data/Log/update", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoUpdate", "args": ["camic", "log"] } + ] + }, + + { + "route": "/data/Freeform/find", + "method": "get", + "handlers": [{ "function": "mongoFind", "args": ["camic", "freeform"] }] + }, + { + "route": "/data/Freeform/post", + "method": "post", + "handlers": [{ "function": "mongoAdd", "args": ["camic", "freeform"] }] + }, + { + "route": "/data/Freeform/delete", + "method": "delete", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoDelete", "args": ["camic", "freeform"] } + ] + }, + { + "route": "/data/Freeform/update", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoUpdate", "args": ["camic", "freeform"] } + ] + }, + + { + "route": "/data/Configuration/find", + "method": "get", + "handlers": [ + { "function": "mongoFind", "args": ["camic", "configuration"] } + ] + }, + { + "route": "/data/Configuration/post", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoAdd", "args": ["camic", "configuration"] } + ] + }, + { + "route": "/data/Configuration/delete", + "method": "delete", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoDelete", "args": ["camic", "configuration"] } + ] + }, + { + "route": "/data/Configuration/update", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoUpdate", "args": ["camic", "configuration"] } + ] + }, + { + "route": "/data/Collection/find", + "method": "get", + "handlers": [{ "function": "mongoFind", "args": ["camic", "collection"] }] + }, + { + "route": "/data/Collection/post", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoAdd", "args": ["camic", "collection"] } + ] + }, + { + "route": "/data/Collection/update", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoUpdate", "args": ["camic", "collection"] } + ] + }, + { + "route": "/data/Collection/delete", + "method": "delete", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "mongoDelete", "args": ["camic", "collection"] } + ] + }, + + { + "route": "/data/User/find", + "method": "get", + "handlers": [{ "function": "mongoFind", "args": ["camic", "user"] }] + }, + { + "route": "/data/User/post", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin"]] }, + { "function": "mongoAdd", "args": ["camic", "user"] } + ] + }, + { + "route": "/data/User/delete", + "method": "delete", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin"]] }, + { "function": "mongoDelete", "args": ["camic", "user"] } + ] + }, + { + "route": "/data/User/update", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin"]] }, + { "function": "mongoUpdate", "args": ["camic", "user"] } + ] + }, + { + "route": "/data/User/wcido", + "method": "get", + "handlers": [{ "function": "wcido", "args": [] }] + }, + { + "route": "/workbench/uploadDataset", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "getDataset", "args": [] } + ] + }, + { + "route": "/workbench/trainModel", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "trainModel", "args": [] } + ] + }, + { + "route": "/workbench/deleteUserData", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "deleteDataset", "args": [] } + ] + }, + { + "route": "/workbench/modelDownload", + "method": "post", + "handlers": [ + { "function": "permissionHandler", "args": [["Admin", "Editor"]] }, + { "function": "sendTrainedModel", "args": [] } + ] + } +] diff --git a/package-lock.json b/package-lock.json index 23b76cd..23f123c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,12 @@ "license": "GPL-3.0", "dependencies": { "@tensorflow/tfjs-node": "^2.8.6", + "accesscontrol": "^2.2.1", "adm-zip": "^0.4.16", "ajv": "^8.6.0", "ajv-keywords": "^5.0.0", "atob": "^2.1.2", + "cookie-parser": "^1.4.5", "dotenv": "^8.6.0", "express": "^4.17.1", "helmet": "^4.6.0", @@ -26,39 +28,224 @@ "devDependencies": { "chai": "^4.3.4", "chai-http": "^4.3.0", - "cookie-parser": "^1.4.4", - "eslint": "^6.8.0", - "eslint-config-google": "^0.14.0", - "eslint-plugin-security": "^1.4.0", - "mocha": "^8.4.0" + "eslint": "^7.30.0", + "eslint-config-airbnb-base": "^14.2.1", + "eslint-plugin-import": "^2.23.4", + "mocha": "^8.4.0", + "prettier": "^2.3.2" } }, "node_modules/@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "dependencies": { - "@babel/highlight": "^7.8.3" + "@babel/highlight": "^7.10.4" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz", - "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==", - "dev": true + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, "node_modules/@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.9.0", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, "node_modules/@tensorflow/tfjs": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-2.8.6.tgz", @@ -162,64 +349,6 @@ "node": ">=8.11.0" } }, - "node_modules/@tensorflow/tfjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@tensorflow/tfjs/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tensorflow/tfjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@tensorflow/tfjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@tensorflow/tfjs/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@tensorflow/tfjs/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -243,12 +372,6 @@ "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==", "dev": true }, - "node_modules/@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, "node_modules/@types/connect": { "version": "3.4.34", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", @@ -301,6 +424,12 @@ "@types/express": "*" } }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -405,10 +534,18 @@ "node": ">= 0.6" } }, + "node_modules/accesscontrol": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/accesscontrol/-/accesscontrol-2.2.1.tgz", + "integrity": "sha512-52EvFk/J9EF+w4mYQoKnOTkEMj01R1U5n2fc1dai6x1xkgOks3DGkx01qQL2cKFxGmE4Tn1krAU3jJA9L1NMkg==", + "dependencies": { + "notation": "^1.3.6" + } + }, "node_modules/acorn": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", - "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -418,10 +555,13 @@ } }, "node_modules/acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, "node_modules/adm-zip": { "version": "0.4.16", @@ -477,27 +617,6 @@ "node": ">=6" } }, - "node_modules/ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "dependencies": { - "type-fest": "^0.11.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", @@ -507,15 +626,17 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { @@ -558,6 +679,42 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "node_modules/array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -568,12 +725,12 @@ } }, "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/asynckit": { @@ -690,6 +847,19 @@ "node": ">= 0.8" } }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -744,25 +914,20 @@ } }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, "node_modules/check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -780,7 +945,6 @@ "dependencies": { "anymatch": "~3.1.1", "braces": "~3.0.2", - "fsevents": "~2.3.1", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -799,24 +963,6 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -827,17 +973,6 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -847,19 +982,20 @@ } }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -883,6 +1019,12 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "node_modules/confusing-browser-globals": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", + "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", + "dev": true + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -919,7 +1061,6 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", - "dev": true, "dependencies": { "cookie": "0.4.0", "cookie-signature": "1.0.6" @@ -951,19 +1092,17 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=4.8" + "node": ">= 8" } }, "node_modules/debug": { @@ -1009,6 +1148,18 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1109,6 +1260,74 @@ "node": ">= 0.8" } }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -1136,55 +1355,61 @@ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "version": "7.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.30.0.tgz", + "integrity": "sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.0.0", + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.2", + "@humanwhocodes/config-array": "^0.5.0", "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.3", + "optionator": "^0.9.1", "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -1192,34 +1417,174 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-google": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", - "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", + "node_modules/eslint-config-airbnb-base": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0", + "eslint-plugin-import": "^2.22.1" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "dependencies": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", + "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-security": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-1.4.0.tgz", - "integrity": "sha512-xlS7P2PLMXeqfhyf3NpqbvbnW04kN8M9NtmhpR3XGyOvt/vNKS7XPXT5EDbwKW9vCjWH4PpfQvgD/+JgN0VJKA==", + "node_modules/eslint-plugin-import/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "dependencies": { - "safe-regex": "^1.1.0" + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-plugin-import/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" } }, "node_modules/eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "dependencies": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" }, "engines": { @@ -1227,26 +1592,38 @@ } }, "node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, "dependencies": { "eslint-visitor-keys": "^1.1.0" }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, "engines": { "node": ">=4" } }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1278,6 +1655,18 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/eslint/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1285,26 +1674,47 @@ "dev": true }, "node_modules/eslint/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, + "node_modules/eslint/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "dependencies": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" }, "engines": { - "node": ">=6.0.0" + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" } }, "node_modules/esprima": { @@ -1321,38 +1731,47 @@ } }, "node_modules/esquery": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.2.0.tgz", - "integrity": "sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "dependencies": { - "estraverse": "^5.0.0" + "estraverse": "^5.1.0" }, "engines": { - "node": ">=8.0" + "node": ">=0.10" } }, "node_modules/esquery/node_modules/estraverse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.0.0.tgz", - "integrity": "sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true, "engines": { "node": ">=4.0" } }, "node_modules/esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "dependencies": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" }, "engines": { "node": ">=4.0" } }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", @@ -1430,20 +1849,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1461,28 +1866,16 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "dependencies": { - "flat-cache": "^2.0.1" + "flat-cache": "^3.0.4" }, "engines": { - "node": ">=4" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/fill-range": { @@ -1536,23 +1929,37 @@ } }, "node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=4" + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.0.tgz", + "integrity": "sha512-XprP7lDrVT+kE2c2YlfiV+IfS9zxukiIOvNamPNsImNhXadSsQEbosItdL9bUQlCZXR13SvPk20BjWSWLA7m4A==", "dev": true }, "node_modules/follow-redirects": { @@ -1641,6 +2048,12 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -1722,6 +2135,20 @@ "node": "*" } }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -1751,15 +2178,18 @@ } }, "node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", "dev": true, "dependencies": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/google-protobuf": { @@ -1767,6 +2197,12 @@ "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.16.0.tgz", "integrity": "sha512-gBY66yYL1wbQMU2r1POkXSXkm035Ni0wFv3vx0K9IEUsJLP9G5rAcFVn0xUXfZneRu6MmDjaw93pt/DE56VOyw==" }, + "node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, "node_modules/growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -1776,13 +2212,45 @@ "node": ">=4.x" } }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-unicode": { @@ -1807,6 +2275,12 @@ "node": ">=10.0.0" } }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "node_modules/http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -2009,134 +2483,99 @@ "webworkify": "^1.4.0" } }, - "node_modules/inquirer": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", - "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^3.0.0", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.5.3", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "dependencies": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "node_modules/ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "engines": { - "node": ">=7.0.0" + "node": ">= 0.10" } }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", "dev": true, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "binary-extensions": "^2.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "node_modules/is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "call-bind": "^1.0.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "node_modules/is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", "dev": true, "engines": { - "node": ">=4" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", "dev": true, "dependencies": { - "binary-extensions": "^2.0.0" + "has": "^1.0.3" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", + "dev": true, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-extglob": { @@ -2178,6 +2617,18 @@ "node": ">=4" } }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2186,6 +2637,18 @@ "node": ">=0.12.0" } }, + "node_modules/is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -2195,11 +2658,48 @@ "node": ">=8" } }, - "node_modules/is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true + "node_modules/is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/isarray": { "version": "1.0.0", @@ -2231,6 +2731,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -2242,6 +2748,18 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/jsonwebtoken": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", @@ -2349,13 +2867,13 @@ } }, "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -2366,6 +2884,21 @@ "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2420,88 +2953,36 @@ }, "node_modules/lodash.isstring": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" - }, - "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, - "node_modules/log-symbols/node_modules/has-flag": { + "node_modules/log-symbols": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "chalk": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, "node_modules/lru-cache": { @@ -2596,15 +3077,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -2713,24 +3185,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/mocha/node_modules/js-yaml": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", @@ -2749,15 +3203,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/mocha/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -2770,21 +3215,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/mocha/node_modules/yargs-parser": { "version": "20.2.4", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", @@ -2803,8 +3233,7 @@ "bson": "^1.1.4", "denque": "^1.4.1", "optional-require": "^1.0.2", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" + "safe-buffer": "^5.1.2" }, "engines": { "node": ">=4" @@ -2818,12 +3247,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, "node_modules/nanoid": { "version": "3.1.20", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", @@ -2879,12 +3302,6 @@ "node": ">= 0.6" } }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "node_modules/node-fetch": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", @@ -2925,6 +3342,18 @@ "nopt": "bin/nopt.js" } }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -2934,6 +3363,11 @@ "node": ">=0.10.0" } }, + "node_modules/notation": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/notation/-/notation-1.3.6.tgz", + "integrity": "sha512-DIuJmrP/Gg1DcXKaApsqcjsJD6jEccqKSfmU3BUx/f1GHsMiTJh70cERwYc64tOmTRTARCeMwkqNNzjh3AHhiw==" + }, "node_modules/npm-bundled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", @@ -2984,6 +3418,73 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", + "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -3003,18 +3504,6 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", @@ -3024,17 +3513,17 @@ } }, "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "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" }, "engines": { "node": ">= 0.8.0" @@ -3089,6 +3578,15 @@ "node": ">=10" } }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3101,6 +3599,19 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -3127,45 +3638,224 @@ } }, "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, "engines": { - "node": "*" + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", + "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", + "engines": { + "node": ">=8.6" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "dependencies": { + "find-up": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/picomatch": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", - "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, "engines": { - "node": ">=8.6" + "node": ">=4" } }, "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "engines": { "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -3270,6 +3960,91 @@ "node": ">=0.10.0" } }, + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "dependencies": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -3311,12 +4086,15 @@ "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, "engines": { - "node": ">=6.5.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, "node_modules/require-directory": { @@ -3340,26 +4118,17 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/rimraf": { @@ -3373,44 +4142,11 @@ "rimraf": "bin.js" } }, - "node_modules/run-async": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", - "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", - "dev": true, - "dependencies": { - "is-promise": "^2.1.0" - }, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/rxjs": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", - "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -3508,24 +4244,24 @@ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "dependencies": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/signal-exit": { @@ -3534,26 +4270,20 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/sparse-bitfield": { @@ -3565,6 +4295,38 @@ "memory-pager": "^1.0.2" } }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", + "dev": true + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -3599,45 +4361,62 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, "dependencies": { - "ansi-regex": "^5.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "dev": true, "dependencies": { - "ansi-regex": "^4.1.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true, "engines": { - "node": ">=6" + "node": ">=4" } }, "node_modules/strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/superagent": { @@ -3677,81 +4456,31 @@ "dev": true }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "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" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/table/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", "dev": true, "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=6" + "node": ">=10.0.0" } }, "node_modules/tar": { @@ -3788,24 +4517,6 @@ "node": ">= 4.0.0" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3825,19 +4536,25 @@ "node": ">=0.6" } }, - "node_modules/tslib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", - "dev": true + "node_modules/tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } }, "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2" + "prelude-ls": "^1.2.1" }, "engines": { "node": ">= 0.8.0" @@ -3853,12 +4570,15 @@ } }, "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/type-is": { @@ -3873,6 +4593,21 @@ "node": ">= 0.6" } }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -3908,6 +4643,16 @@ "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", "dev": true }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -3922,15 +4667,34 @@ "integrity": "sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g==" }, "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { "isexe": "^2.0.0" }, "bin": { - "which": "bin/which" + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/wide-align": { @@ -4008,61 +4772,11 @@ "node": ">=10" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -4128,94 +4842,193 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { - "@babel/highlight": "^7.8.3" + "@babel/highlight": "^7.10.4" } }, "@babel/helper-validator-identifier": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz", - "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", "dev": true }, "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.9.0", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" - } - }, - "@tensorflow/tfjs": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-2.8.6.tgz", - "integrity": "sha512-/Hk3YCAreNicuQJsAIG32UGHaQj8UwX8y8ZrKVb/CrXOhrRyZmxGSZt9KMVe8MDoydenuGhZCqJUIaWdIKIA5g==", - "requires": { - "@tensorflow/tfjs-backend-cpu": "2.8.6", - "@tensorflow/tfjs-backend-webgl": "2.8.6", - "@tensorflow/tfjs-converter": "2.8.6", - "@tensorflow/tfjs-core": "2.8.6", - "@tensorflow/tfjs-data": "2.8.6", - "@tensorflow/tfjs-layers": "2.8.6", - "argparse": "^1.0.10", - "chalk": "^4.1.0", - "core-js": "3", - "regenerator-runtime": "^0.13.5", - "yargs": "^16.0.3" }, "dependencies": { "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "requires": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { - "color-name": "~1.1.4" + "color-name": "1.1.3" } }, "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "requires": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "@tensorflow/tfjs": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/@tensorflow/tfjs/-/tfjs-2.8.6.tgz", + "integrity": "sha512-/Hk3YCAreNicuQJsAIG32UGHaQj8UwX8y8ZrKVb/CrXOhrRyZmxGSZt9KMVe8MDoydenuGhZCqJUIaWdIKIA5g==", + "requires": { + "@tensorflow/tfjs-backend-cpu": "2.8.6", + "@tensorflow/tfjs-backend-webgl": "2.8.6", + "@tensorflow/tfjs-converter": "2.8.6", + "@tensorflow/tfjs-core": "2.8.6", + "@tensorflow/tfjs-data": "2.8.6", + "@tensorflow/tfjs-layers": "2.8.6", + "argparse": "^1.0.10", + "chalk": "^4.1.0", + "core-js": "3", + "regenerator-runtime": "^0.13.5", + "yargs": "^16.0.3" + } + }, "@tensorflow/tfjs-backend-cpu": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-2.8.6.tgz", @@ -4305,12 +5118,6 @@ "integrity": "sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw==", "dev": true }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, "@types/connect": { "version": "3.4.34", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", @@ -4363,6 +5170,12 @@ "@types/express": "*" } }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -4463,17 +5276,26 @@ "negotiator": "0.6.2" } }, + "accesscontrol": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/accesscontrol/-/accesscontrol-2.2.1.tgz", + "integrity": "sha512-52EvFk/J9EF+w4mYQoKnOTkEMj01R1U5n2fc1dai6x1xkgOks3DGkx01qQL2cKFxGmE4Tn1krAU3jJA9L1NMkg==", + "requires": { + "notation": "^1.3.6" + } + }, "acorn": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", - "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "requires": {} }, "adm-zip": { "version": "0.4.16", @@ -4513,35 +5335,17 @@ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", "dev": true }, - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - }, - "dependencies": { - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - } - } - }, "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, "anymatch": { @@ -4581,6 +5385,30 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + } + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -4588,9 +5416,9 @@ "dev": true }, "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, "asynckit": { @@ -4686,6 +5514,16 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -4728,22 +5566,14 @@ } }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -4766,25 +5596,10 @@ "readdirp": "~3.5.0" } }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "cliui": { "version": "7.0.4", @@ -4794,16 +5609,6 @@ "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - } } }, "code-point-at": { @@ -4812,19 +5617,17 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "combined-stream": { "version": "1.0.8", @@ -4845,6 +5648,12 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "confusing-browser-globals": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", + "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", + "dev": true + }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -4872,7 +5681,6 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", - "dev": true, "requires": { "cookie": "0.4.0", "cookie-signature": "1.0.6" @@ -4900,16 +5708,14 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, "debug": { @@ -4946,6 +5752,15 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -5019,6 +5834,59 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -5043,52 +5911,55 @@ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "version": "7.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.30.0.tgz", + "integrity": "sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.2", + "@humanwhocodes/config-array": "^0.5.0", "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", "debug": "^4.0.1", "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.3", + "optionator": "^0.9.1", "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -5120,6 +5991,15 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5127,62 +6007,197 @@ "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, - "eslint-config-google": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz", - "integrity": "sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==", - "dev": true + "eslint-config-airbnb-base": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.2" + } }, - "eslint-plugin-security": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-1.4.0.tgz", - "integrity": "sha512-xlS7P2PLMXeqfhyf3NpqbvbnW04kN8M9NtmhpR3XGyOvt/vNKS7XPXT5EDbwKW9vCjWH4PpfQvgD/+JgN0VJKA==", + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + } + }, + "eslint-module-utils": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", + "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", "dev": true, "requires": { - "safe-regex": "^1.1.0" + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } } }, "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, "espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, "esprima": { @@ -5192,29 +6207,37 @@ "dev": true }, "esquery": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.2.0.tgz", - "integrity": "sha512-weltsSqdeWIX9G2qQZz7KlTRJdkkOCTPgLYJUz1Hacf48R4YOwGPHO3+ORfWedqJKbq5WQmsgK90n+pFLIKt/Q==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { - "estraverse": "^5.0.0" + "estraverse": "^5.1.0" }, "dependencies": { "estraverse": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.0.0.tgz", - "integrity": "sha512-j3acdrMzqrxmJTNj5dbr1YbjacrYgAxVMeF0gK16E3j494mOe7xygM/ZLIguEQ0ETwAg2hlJCtHRGav+y0Ny5A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true } } }, "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, "estraverse": { @@ -5282,17 +6305,6 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5310,22 +6322,13 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { - "flat-cache": "^2.0.1" + "flat-cache": "^3.0.4" } }, "fill-range": { @@ -5367,20 +6370,30 @@ "dev": true }, "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.0.tgz", + "integrity": "sha512-XprP7lDrVT+kE2c2YlfiV+IfS9zxukiIOvNamPNsImNhXadSsQEbosItdL9bUQlCZXR13SvPk20BjWSWLA7m4A==", "dev": true }, "follow-redirects": { @@ -5453,6 +6466,12 @@ "dev": true, "optional": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -5518,6 +6537,17 @@ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -5541,12 +6571,12 @@ } }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } }, "google-protobuf": { @@ -5554,16 +6584,42 @@ "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.16.0.tgz", "integrity": "sha512-gBY66yYL1wbQMU2r1POkXSXkm035Ni0wFv3vx0K9IEUsJLP9G5rAcFVn0xUXfZneRu6MmDjaw93pt/DE56VOyw==" }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, "has-unicode": { @@ -5582,6 +6638,12 @@ "resolved": "https://registry.npmjs.org/helmet/-/helmet-4.6.0.tgz", "integrity": "sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==" }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "http-errors": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", @@ -5744,93 +6806,11 @@ }, "inkjet": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/inkjet/-/inkjet-2.1.2.tgz", - "integrity": "sha1-2e/Nvsf//XMO4joS9II/A+Wiig8=", - "requires": { - "imageinfo": "^1.0.4", - "webworkify": "^1.4.0" - } - }, - "inquirer": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", - "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^3.0.0", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.5.3", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "resolved": "https://registry.npmjs.org/inkjet/-/inkjet-2.1.2.tgz", + "integrity": "sha1-2e/Nvsf//XMO4joS9II/A+Wiig8=", + "requires": { + "imageinfo": "^1.0.4", + "webworkify": "^1.4.0" } }, "ip-regex": { @@ -5844,6 +6824,18 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "dev": true + }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -5853,6 +6845,36 @@ "binary-extensions": "^2.0.0" } }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", + "dev": true + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -5880,23 +6902,54 @@ "ip-regex": "^2.0.0" } }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "dev": true + }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", "dev": true }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -5924,6 +6977,12 @@ "esprima": "^4.0.0" } }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -5935,6 +6994,15 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, "jsonwebtoken": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", @@ -6035,13 +7103,13 @@ } }, "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, "limiter": { @@ -6049,6 +7117,18 @@ "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -6103,11 +7183,23 @@ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, "log-symbols": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", @@ -6115,57 +7207,6 @@ "dev": true, "requires": { "chalk": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "lru-cache": { @@ -6241,12 +7282,6 @@ "mime-db": "1.42.0" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -6341,18 +7376,6 @@ } } }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "js-yaml": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", @@ -6368,12 +7391,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -6383,15 +7400,6 @@ "has-flag": "^4.0.0" } }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, "yargs-parser": { "version": "20.2.4", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", @@ -6418,12 +7426,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, "nanoid": { "version": "3.1.20", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", @@ -6466,12 +7468,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "node-fetch": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", @@ -6503,12 +7499,29 @@ "osenv": "^0.1.4" } }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "notation": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/notation/-/notation-1.3.6.tgz", + "integrity": "sha512-DIuJmrP/Gg1DcXKaApsqcjsJD6jEccqKSfmU3BUx/f1GHsMiTJh70cERwYc64tOmTRTARCeMwkqNNzjh3AHhiw==" + }, "npm-bundled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", @@ -6553,6 +7566,52 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", + "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + } + }, + "object.values": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -6569,32 +7628,23 @@ "wrappy": "1" } }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, "optional-require": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==" }, "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "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": { @@ -6634,6 +7684,12 @@ "p-limit": "^3.0.2" } }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6643,48 +7699,193 @@ "callsites": "^3.0.0" } }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picomatch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", + "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==" + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "picomatch": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", - "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==" - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", "dev": true }, "process-nextick-args": { @@ -6769,6 +7970,72 @@ } } }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -6806,9 +8073,9 @@ "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "require-directory": { @@ -6826,22 +8093,16 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", @@ -6850,38 +8111,11 @@ "glob": "^7.1.3" } }, - "run-async": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", - "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "rxjs": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", - "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -6969,18 +8203,18 @@ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "signal-exit": { @@ -6989,22 +8223,14 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" } }, "sparse-bitfield": { @@ -7016,6 +8242,38 @@ "memory-pager": "^1.0.2" } }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", + "dev": true + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -7042,39 +8300,46 @@ "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - } } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "superagent": { @@ -7113,67 +8378,25 @@ } }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - } + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" } }, "tar": { @@ -7204,21 +8427,6 @@ "lodash.defaults": "^4.0.1" } }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7232,19 +8440,25 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, - "tslib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", - "dev": true + "tsconfig-paths": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", + "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } }, "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "prelude-ls": "^1.2.1" } }, "type-detect": { @@ -7254,9 +8468,9 @@ "dev": true }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, "type-is": { @@ -7268,6 +8482,18 @@ "mime-types": "~2.1.24" } }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -7297,6 +8523,16 @@ "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", "dev": true }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -7308,14 +8544,27 @@ "integrity": "sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g==" }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, "wide-align": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", @@ -7373,37 +8622,6 @@ "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - } } }, "wrappy": { @@ -7411,15 +8629,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 059fe07..ebbff4a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "caracal.js", "scripts": { "test": "mocha test/* --exit", - "lint": "eslint *.js handlers/*.js test/**/*.js", + "lint": "eslint handlers/*.js service/**/*.js test/**/*.js --fix", "lint-fix": "eslint *.js handlers/*.js test/**/*.js --fix", "start": "node caracal.js" }, @@ -21,6 +21,7 @@ "homepage": "https://github.com/camicroscope/caboodle#readme", "dependencies": { "@tensorflow/tfjs-node": "^2.8.6", + "accesscontrol": "^2.2.1", "adm-zip": "^0.4.16", "ajv": "^8.6.0", "ajv-keywords": "^5.0.0", @@ -33,15 +34,16 @@ "jsonwebtoken": "^8.5.1", "jwks-rsa": "^1.12.3", "mongodb": "^3.6.6", + "cookie-parser": "^1.4.5", "throng": "^4.0.0" }, "devDependencies": { "chai": "^4.3.4", "chai-http": "^4.3.0", - "cookie-parser": "^1.4.4", - "eslint": "^6.8.0", - "eslint-config-google": "^0.14.0", - "eslint-plugin-security": "^1.4.0", - "mocha": "^8.4.0" + "eslint": "^7.30.0", + "eslint-config-airbnb-base": "^14.2.1", + "eslint-plugin-import": "^2.23.4", + "mocha": "^8.4.0", + "prettier": "^2.3.2" } } diff --git a/resources.json b/resources.json new file mode 100644 index 0000000..60b7d41 --- /dev/null +++ b/resources.json @@ -0,0 +1,37 @@ +{ + "slide": ["read", "create", "delete", "update"], + "request": ["read", "create", "delete"], + "presetLabel": ["create", "update", "delete"], + "template": ["read", "create", "delete", "update"], + "heatmap": ["read", "types", "create", "delete", "update"], + "heatmapEdit": ["read", "create", "delete", "update"], + "log": ["read", "create", "delete", "update"], + "freeform": ["read", "create", "delete", "update"], + "configuration": ["read", "create", "delete", "update"], + "collection": ["read", "create", "update", "delete"], + "user": ["read", "create", "delete", "update", "wcido"], + "middleware": [ + "loader.login", + "loader.slide.delete", + "loader.proxyHandlehr", + "googleAuth", + "img.iip.raw", + "data" + ], + "mark": [ + "read", + "create", + "delete", + "update", + "types", + "multi", + "spatial", + "findMarkTypes" + ], + "workbench": [ + "uploadDataset", + "trainModel", + "deleteUserData", + "modelDownload" + ] +} diff --git a/routes.json b/routes.json new file mode 100644 index 0000000..6676d9b --- /dev/null +++ b/routes.json @@ -0,0 +1,957 @@ +[ + { + "method": "static", + "use": "static" + }, + { + "method": "static", + "use": "camicroscope" + }, + { + "method": "use", + "route": "/loader/", + "access": { + "entity": "middleware", + "operation": "loader.login" + }, + "handlers": [ + { + "function": "loginHandler", + "args": [] + } + ] + }, + { + "method": "use", + "route": "/loader/slide/delete", + "access": { + "entity": "middleware", + "operation": "loader.slide.delete" + }, + "handlers": [] + }, + { + "method": "use", + "route": "/loader/", + "access": { + "entity": "middleware", + "operation": "loader.proxyHandler" + }, + "handlers": [ + { + "function": "proxyHandler", + "args": ["http://ca-load:4000/"] + } + ] + }, + { + "method": "use", + "route": "/googleAuth/", + "access": { + "entity": "middleware", + "operation": "googleAuth" + }, + "handlers": [ + { + "function": "proxyHandler", + "args": ["http://ca-load:4001/"] + } + ] + }, + { + "method": "use", + "route": "/img/IIP/raw/", + "access": { + "entity": "middleware", + "operation": "img.iip.raw" + }, + "handlers": [ + { + "function": "loginHandler", + "args": [] + }, + { + "function": "iipHandler", + "args": [] + } + ] + }, + { + "route": "/data", + "method": "use", + "access": { + "entity": "middleware", + "operation": "data" + }, + "handlers": [ + { + "function": "loginHandler", + "args": [] + }, + { + "function": "sanitizeBody", + "args": [] + } + ] + }, + { + "route": "/data/Slide/find", + "method": "get", + "access": { + "entity": "slide", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "slide"] + }, + { + "function": "filterHandler", + "args": ["data", "userFilter", "filter"] + } + ] + }, + { + "route": "/data/Slide/post", + "method": "post", + "access": { + "entity": "slide", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "slide"] + } + ] + }, + { + "route": "/data/Slide/delete", + "method": "delete", + "access": { + "entity": "slide", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "slide"] + }, + { + "function": "editHandler", + "args": ["data", "userFilter", "filter"] + }, + { + "function": "mongoDelete", + "args": ["camic", "slide"] + } + ] + }, + { + "route": "/data/Slide/update", + "method": "post", + "access": { + "entity": "slide", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "slide"] + }, + { + "function": "editHandler", + "args": ["data", "userFilter", "filter"] + }, + { + "function": "mongoUpdate", + "args": ["camic", "slide"] + } + ] + }, + { + "route": "/data/Request/find", + "method": "get", + "access": { + "entity": "request", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "request"] + } + ] + }, + { + "route": "/data/Request/post", + "method": "post", + "access": { + "entity": "request", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "request"] + } + ] + }, + { + "route": "/data/Request/delete", + "method": "delete", + "access": { + "entity": "request", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "request"] + }, + { + "function": "editHandler", + "args": ["data", "userFilter", "filter"] + }, + { + "function": "mongoDelete", + "args": ["camic", "request"] + } + ] + }, + { + "route": "/data/Mark/find", + "method": "get", + "access": { + "entity": "mark", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "mark"] + } + ] + }, + { + "route": "/data/Mark/post", + "method": "post", + "access": { + "entity": "mark", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "mark"] + } + ] + }, + { + "route": "/data/Mark/delete", + "method": "delete", + "access": { + "entity": "mark", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "mark"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "mongoDelete", + "args": ["camic", "mark"] + } + ] + }, + { + "route": "/data/Mark/update", + "method": "post", + "access": { + "entity": "mark", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "mark"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "mongoUpdate", + "args": ["camic", "mark"] + } + ] + }, + { + "route": "/data/Mark/types", + "method": "get", + "access": { + "entity": "mark", + "operation": "types" + }, + "handlers": [ + { + "function": "mongoDistinct", + "args": ["camic", "mark", "provenance.analysis"] + } + ] + }, + { + "route": "/data/Mark/multi", + "method": "post", + "access": { + "entity": "mark", + "operation": "multi" + }, + "handlers": [ + { + "function": "markMulti", + "args": [] + } + ] + }, + { + "route": "/data/Mark/spatial", + "method": "get", + "access": { + "entity": "mark", + "operation": "spatial" + }, + "handlers": [ + { + "function": "markSpatial", + "args": [] + } + ] + }, + { + "route": "/data/Mark/findMarkTypes", + "method": "get", + "access": { + "entity": "mark", + "operation": "findMarkTypes" + }, + "handlers": [ + { + "function": "findMarkTypes", + "args": [] + } + ] + }, + { + "route": "/data/Presetlabels/add", + "method": "post", + "access": { + "entity": "presetLabel", + "operation": "create" + }, + "handlers": [ + { + "function": "addPresetlabels", + "args": [] + } + ] + }, + { + "route": "/data/Presetlabels/update", + "method": "post", + "access": { + "entity": "presetLabel", + "operation": "update" + }, + "handlers": [ + { + "function": "updatePresetlabels", + "args": [] + } + ] + }, + { + "route": "/data/Presetlabels/remove", + "method": "post", + "access": { + "entity": "presetLabel", + "operation": "delete" + }, + "handlers": [ + { + "function": "removePresetlabels", + "args": [] + } + ] + }, + { + "route": "/data/Template/find", + "method": "get", + "access": { + "entity": "template", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "template"] + } + ] + }, + { + "route": "/data/Template/post", + "method": "post", + "access": { + "entity": "template", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "template"] + } + ] + }, + { + "route": "/data/Template/delete", + "method": "delete", + "access": { + "entity": "template", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoDelete", + "args": ["camic", "template"] + } + ] + }, + { + "route": "/data/Template/update", + "method": "post", + "access": { + "entity": "template", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoUpdate", + "args": ["camic", "template"] + } + ] + }, + { + "route": "/data/Heatmap/find", + "method": "get", + "access": { + "entity": "heatmap", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + } + ] + }, + { + "route": "/data/Heatmap/types", + "method": "get", + "access": { + "entity": "heatmap", + "operation": "types" + }, + "handlers": [ + { + "function": "heatmapTypes", + "args": [] + } + ] + }, + { + "route": "/data/Heatmap/post", + "method": "post", + "access": { + "entity": "heatmap", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "heatmap"] + } + ] + }, + { + "route": "/data/Heatmap/delete", + "method": "delete", + "access": { + "entity": "heatmap", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "mongoDelete", + "args": ["camic", "heatmap"] + } + ] + }, + { + "route": "/data/Heatmap/update", + "method": "post", + "access": { + "entity": "heatmap", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "mongoUpdate", + "args": ["camic", "heatmap"] + } + ] + }, + { + "route": "/data/HeatmapEdit/find", + "method": "get", + "access": { + "entity": "heatmapEdit", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmapEdit"] + } + ] + }, + { + "route": "/data/HeatmapEdit/post", + "method": "post", + "access": { + "entity": "heatmapEdit", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "heatmapEdit"] + } + ] + }, + { + "route": "/data/HeatmapEdit/delete", + "method": "delete", + "access": { + "entity": "heatmapEdit", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "mongoDelete", + "args": ["camic", "heatmapEdit"] + } + ] + }, + { + "route": "/data/HeatmapEdit/update", + "method": "post", + "access": { + "entity": "heatmapEdit", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "mongoUpdate", + "args": ["camic", "heatmapEdit"] + } + ] + }, + { + "route": "/data/Log/find", + "method": "get", + "access": { + "entity": "log", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "log"] + } + ] + }, + { + "route": "/data/Log/post", + "method": "post", + "access": { + "entity": "log", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "log"] + } + ] + }, + { + "route": "/data/Log/delete", + "method": "delete", + "access": { + "entity": "log", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoDelete", + "args": ["camic", "log"] + } + ] + }, + { + "route": "/data/Log/update", + "method": "post", + "access": { + "entity": "log", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoUpdate", + "args": ["camic", "log"] + } + ] + }, + { + "route": "/data/Freeform/find", + "method": "get", + "access": { + "entity": "freeform", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "freeform"] + } + ] + }, + { + "route": "/data/Freeform/post", + "method": "post", + "access": { + "entity": "freeform", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "freeform"] + } + ] + }, + { + "route": "/data/Freeform/delete", + "method": "delete", + "access": { + "entity": "freeform", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoDelete", + "args": ["camic", "freeform"] + } + ] + }, + { + "route": "/data/Freeform/update", + "method": "post", + "access": { + "entity": "freeform", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoUpdate", + "args": ["camic", "freeform"] + } + ] + }, + { + "route": "/data/Configuration/find", + "method": "get", + "access": { + "entity": "configuration", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "configuration"] + } + ] + }, + { + "route": "/data/Configuration/post", + "method": "post", + "access": { + "entity": "configuration", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "configuration"] + } + ] + }, + { + "route": "/data/Configuration/delete", + "method": "delete", + "access": { + "entity": "configuration", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoDelete", + "args": ["camic", "configuration"] + } + ] + }, + { + "route": "/data/Configuration/update", + "method": "post", + "access": { + "entity": "configuration", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoUpdate", + "args": ["camic", "configuration"] + } + ] + }, + { + "route": "/data/Collection/find", + "method": "get", + "access": { + "entity": "collection", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "collection"] + } + ] + }, + { + "route": "/data/Collection/post", + "method": "post", + "access": { + "entity": "collection", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "collection"] + } + ] + }, + { + "route": "/data/Collection/update", + "method": "post", + "access": { + "entity": "collection", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoUpdate", + "args": ["camic", "collection"] + } + ] + }, + { + "route": "/data/Collection/delete", + "method": "delete", + "access": { + "entity": "collection", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoDelete", + "args": ["camic", "collection"] + } + ] + }, + { + "route": "/data/User/find", + "method": "get", + "access": { + "entity": "user", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "user"] + } + ] + }, + { + "route": "/data/User/post", + "method": "post", + "access": { + "entity": "user", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "user"] + } + ] + }, + { + "route": "/data/User/delete", + "method": "delete", + "access": { + "entity": "user", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoDelete", + "args": ["camic", "user"] + } + ] + }, + { + "route": "/data/User/update", + "method": "post", + "access": { + "entity": "user", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoUpdate", + "args": ["camic", "user"] + } + ] + }, + { + "route": "/data/User/wcido", + "method": "get", + "access": { + "entity": "user", + "operation": "wcido" + }, + "handlers": [ + { + "function": "wcido", + "args": [] + } + ] + }, + { + "route": "/workbench/uploadDataset", + "method": "post", + "access": { + "entity": "workbench", + "operation": "uploadDataset" + }, + "handlers": [ + { + "function": "getDataset", + "args": [] + } + ] + }, + { + "route": "/workbench/trainModel", + "method": "post", + "access": { + "entity": "workbench", + "operation": "trainModel" + }, + "handlers": [ + { + "function": "trainModel", + "args": [] + } + ] + }, + { + "route": "/workbench/deleteUserData", + "method": "post", + "access": { + "entity": "workbench", + "operation": "deleteUserData" + }, + "handlers": [ + { + "function": "deleteDataset", + "args": [] + } + ] + }, + { + "route": "/workbench/modelDownload", + "method": "post", + "access": { + "entity": "workbench", + "operation": "modelDownload" + }, + "handlers": [ + { + "function": "sendTrainedModel", + "args": [] + } + ] + } +] diff --git a/routes.json.example b/routes.json.example index 2290e15..534364a 100644 --- a/routes.json.example +++ b/routes.json.example @@ -1,462 +1,1102 @@ [ { - "method":"static", - "use":"static" - },{ - "method":"static", - "use":"camicroscope" + "method": "static", + "use": "static" }, - { - "method":"use", + "method": "static", + "use": "camicroscope" + }, + { + "method": "use", "route": "/loader/", - "handlers":[ - {"function": "loginHandler", "args":[]}, - {"function":"permissionHandler", "args": [["Admin", "Editor"]]} + "access": { + "entity": "middleware", + "operation": "loader.login" + }, + "handlers": [ + { + "function": "loginHandler", + "args": [] + }, + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + } ] - },{ - "method":"use", + }, + { + "method": "use", "route": "/loader/slide/delete", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin"]]} + "access": { + "entity": "middleware", + "operation": "loader.slide.delete" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin"]] + } ] - },{ - "method":"use", + }, + { + "method": "use", "route": "/loader/", - "handlers":[ - {"function":"proxyHandler", "args": ["http://ca-load:4000/"]} + "access": { + "entity": "middleware", + "operation": "loader.proxyHandler" + }, + "handlers": [ + { + "function": "proxyHandler", + "args": ["http://ca-load:4000/"] + } ] - },{ - "method":"use", + }, + { + "method": "use", "route": "/googleAuth/", - "handlers":[ - {"function":"proxyHandler", "args": ["http://ca-load:4001/"]} + "access": { + "entity": "middleware", + "operation": "googleAuth" + }, + "handlers": [ + { + "function": "proxyHandler", + "args": ["http://ca-load:4001/"] + } ] }, - { - "method":"use", + "method": "use", "route": "/img/IIP/raw/", - "handlers":[ - {"function": "loginHandler", "args":[]}, - {"function":"iipHandler", "args": []} - ] - }, - - { - "route":"/data", - "method":"use", - "handlers":[ - {"function":"loginHandler", "args": []}, - {"function":"sanitizeBody", "args": []} - ] - }, - - { - "route":"/data/Slide/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "slide"]}, - {"function":"filterHandler", "args": ["data", "userFilter", "filter"]} - ] - },{ - "route":"/data/Slide/post", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoAdd", "args": ["camic", "slide"]} - ] - },{ - "route":"/data/Slide/delete", - "method":"delete", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoFind", "args": ["camic", "slide"]}, - {"function":"editHandler", "args": ["data", "userFilter", "filter"]}, - {"function":"mongoDelete", "args": ["camic", "slide"]} - ] - },{ - "route":"/data/Slide/update", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoFind", "args": ["camic", "slide"]}, - {"function":"editHandler", "args": ["data", "userFilter", "filter"]}, - {"function":"mongoUpdate", "args": ["camic", "slide"]} - ] - }, - - { - "route":"/data/Request/find", - "method":"get", - "handlers":[ - {"function":"permissionHandler", "args": [["Editor", "Admin"]]}, - {"function":"mongoFind", "args": ["camic", "request"]} - ] - },{ - "route":"/data/Request/post", - "method":"post", - "handlers":[ - {"function":"mongoAdd", "args": ["camic", "request"]} - ] - },{ - "route":"/data/Request/delete", - "method":"delete", - "handlers":[ - {"function":"permissionHandler", "args": [["Editor", "Admin"]]}, - {"function":"mongoFind", "args": ["camic", "request"]}, - {"function":"editHandler", "args": ["data", "userFilter", "filter"]}, - {"function":"mongoDelete", "args": ["camic", "request"]} - ] - }, - - { - "route":"/data/Mark/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "mark"]} - ] - },{ - "route":"/data/Mark/post", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoAdd", "args": ["camic", "mark"]} - ] - },{ - "route":"/data/Mark/delete", - "method":"delete", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "mark"]}, - {"function":"editHandler", "args": ["data"]}, - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoDelete", "args": ["camic", "mark"]} - ] - },{ - "route":"/data/Mark/update", - "method":"post", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "mark"]}, - {"function":"editHandler", "args": ["data"]}, - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoUpdate", "args": ["camic", "mark"]} - ] - },{ - "route":"/data/Mark/types", - "method":"get", - "handlers":[ - {"function":"mongoDistinct", "args": ["camic", "mark", "provenance.analysis"]} - ] - },{ - "route":"/data/Mark/multi", - "method":"post", - "handlers":[ - {"function":"markMulti", "args": []} - ] - },{ - "route":"/data/Mark/spatial", - "method":"get", - "handlers":[ - {"function":"markSpatial", "args": []} - ] - },{ - "route":"/data/Mark/findMarkTypes", - "method":"get", - "handlers":[ - {"function":"findMarkTypes", "args": []} - ] - },{ - "route":"/data/Presetlabels/add", - "method":"post", - "handlers":[ - {"function":"addPresetlabels", "args": []} - ] - },{ - "route":"/data/Presetlabels/update", - "method":"post", - "handlers":[ - {"function":"updatePresetlabels", "args": []} - ] - },{ - "route":"/data/Presetlabels/remove", - "method":"post", - "handlers":[ - {"function":"removePresetlabels", "args": []} - ] - }, - { - "route":"/data/Template/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "template"]} - ] - },{ - "route":"/data/Template/post", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoAdd", "args": ["camic", "template"]} - ] - },{ - "route":"/data/Template/delete", - "method":"delete", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoDelete", "args": ["camic", "template"]} - ] - },{ - "route":"/data/Template/update", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin"]]}, - {"function":"mongoUpdate", "args": ["camic", "template"]} - ] - }, - - { - "route":"/data/Heatmap/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "heatmap"]} - ] - },{ - "route":"/data/Heatmap/types", - "method":"get", - "handlers":[ - {"function":"heatmapTypes", "args": []} - ] - },{ - "route":"/data/Heatmap/post", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoAdd", "args": ["camic", "heatmap"]} - ] - },{ - "route":"/data/Heatmap/delete", - "method":"delete", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "heatmap"]}, - {"function":"editHandler", "args": ["data"]}, - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoDelete", "args": ["camic", "heatmap"]} - ] - },{ - "route":"/data/Heatmap/update", - "method":"post", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "heatmap"]}, - {"function":"editHandler", "args": ["data"]}, - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoUpdate", "args": ["camic", "heatmap"]} - ] - }, - - { - "route":"/data/HeatmapEdit/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "heatmapEdit"]} - ] - },{ - "route":"/data/HeatmapEdit/post", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoAdd", "args": ["camic", "heatmapEdit"]} - ] - },{ - "route":"/data/HeatmapEdit/delete", - "method":"delete", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "heatmap"]}, - {"function":"editHandler", "args": ["data"]}, - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoDelete", "args": ["camic", "heatmapEdit"]} - ] - },{ - "route":"/data/HeatmapEdit/update", - "method":"post", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "heatmap"]}, - {"function":"editHandler", "args": ["data"]}, - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoUpdate", "args": ["camic", "heatmapEdit"]} - ] - }, - - { - "route":"/data/Log/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "log"]} - ] - },{ - "route":"/data/Log/post", - "method":"post", - "handlers":[ - {"function":"mongoAdd", "args": ["camic", "log"]} - ] - },{ - "route":"/data/Log/delete", - "method":"delete", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoDelete", "args": ["camic", "log"]} - ] - },{ - "route":"/data/Log/update", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoUpdate", "args": ["camic", "log"]} - ] - }, - - { - "route":"/data/Freeform/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "freeform"]} - ] - },{ - "route":"/data/Freeform/post", - "method":"post", - "handlers":[ - {"function":"mongoAdd", "args": ["camic", "freeform"]} - ] - },{ - "route":"/data/Freeform/delete", - "method":"delete", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoDelete", "args": ["camic", "freeform"]} - ] - },{ - "route":"/data/Freeform/update", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoUpdate", "args": ["camic", "freeform"]} - ] - }, - - { - "route":"/data/Configuration/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "configuration"]} - ] - },{ - "route":"/data/Configuration/post", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoAdd", "args": ["camic", "configuration"]} - ] - },{ - "route":"/data/Configuration/delete", - "method":"delete", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoDelete", "args": ["camic", "configuration"]} - ] - },{ - "route":"/data/Configuration/update", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoUpdate", "args": ["camic", "configuration"]} - ] - },{ - "route":"/data/Collection/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "collection"]} - ] - },{ - "route":"/data/Collection/post", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoAdd", "args": ["camic", "collection"]} - ] - },{ - "route":"/data/Collection/update", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoUpdate", "args": ["camic", "collection"]} - ] - },{ - "route":"/data/Collection/delete", - "method":"delete", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"mongoDelete", "args": ["camic", "collection"]} - ] - }, - - { - "route":"/data/User/find", - "method":"get", - "handlers":[ - {"function":"mongoFind", "args": ["camic", "user"]} - ] - },{ - "route":"/data/User/post", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin"]]}, - {"function":"mongoAdd", "args": ["camic", "user"]} - ] - },{ - "route":"/data/User/delete", - "method":"delete", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin"]]}, - {"function":"mongoDelete", "args": ["camic", "user"]} - ] - },{ - "route":"/data/User/update", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin"]]}, - {"function":"mongoUpdate", "args": ["camic", "user"]} - ] - },{ - "route":"/data/User/wcido", - "method":"get", - "handlers":[ - {"function":"wcido", "args": []} - ] - },{ - "route":"/workbench/uploadDataset", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"getDataset", "args": []} - ] - },{ - "route":"/workbench/trainModel", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"trainModel", "args": []} - ] - },{ - "route":"/workbench/deleteUserData", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"deleteDataset", "args": []} - ] - },{ - "route":"/workbench/modelDownload", - "method":"post", - "handlers":[ - {"function":"permissionHandler", "args": [["Admin", "Editor"]]}, - {"function":"sendTrainedModel", "args": []} + "access": { + "entity": "middleware", + "operation": "img.iip.raw" + }, + "handlers": [ + { + "function": "loginHandler", + "args": [] + }, + { + "function": "iipHandler", + "args": [] + } + ] + }, + { + "route": "/data", + "method": "use", + "access": { + "entity": "middleware", + "operation": "data" + }, + "handlers": [ + { + "function": "loginHandler", + "args": [] + }, + { + "function": "sanitizeBody", + "args": [] + } + ] + }, + { + "route": "/data/Slide/find", + "method": "get", + "access": { + "entity": "slide", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "slide"] + }, + { + "function": "filterHandler", + "args": ["data", "userFilter", "filter"] + } + ] + }, + { + "route": "/data/Slide/post", + "method": "post", + "access": { + "entity": "slide", + "operation": "create" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoAdd", + "args": ["camic", "slide"] + } + ] + }, + { + "route": "/data/Slide/delete", + "method": "delete", + "access": { + "entity": "slide", + "operation": "delete" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoFind", + "args": ["camic", "slide"] + }, + { + "function": "editHandler", + "args": ["data", "userFilter", "filter"] + }, + { + "function": "mongoDelete", + "args": ["camic", "slide"] + } + ] + }, + { + "route": "/data/Slide/update", + "method": "post", + "access": { + "entity": "slide", + "operation": "update" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoFind", + "args": ["camic", "slide"] + }, + { + "function": "editHandler", + "args": ["data", "userFilter", "filter"] + }, + { + "function": "mongoUpdate", + "args": ["camic", "slide"] + } + ] + }, + { + "route": "/data/Request/find", + "method": "get", + "access": { + "entity": "request", + "operation": "read" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Editor", "Admin"]] + }, + { + "function": "mongoFind", + "args": ["camic", "request"] + } + ] + }, + { + "route": "/data/Request/post", + "method": "post", + "access": { + "entity": "request", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "request"] + } + ] + }, + { + "route": "/data/Request/delete", + "method": "delete", + "access": { + "entity": "request", + "operation": "delete" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Editor", "Admin"]] + }, + { + "function": "mongoFind", + "args": ["camic", "request"] + }, + { + "function": "editHandler", + "args": ["data", "userFilter", "filter"] + }, + { + "function": "mongoDelete", + "args": ["camic", "request"] + } + ] + }, + { + "route": "/data/Mark/find", + "method": "get", + "access": { + "entity": "mark", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "mark"] + } + ] + }, + { + "route": "/data/Mark/post", + "method": "post", + "access": { + "entity": "mark", + "operation": "create" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoAdd", + "args": ["camic", "mark"] + } + ] + }, + { + "route": "/data/Mark/delete", + "method": "delete", + "access": { + "entity": "mark", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "mark"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoDelete", + "args": ["camic", "mark"] + } + ] + }, + { + "route": "/data/Mark/update", + "method": "post", + "access": { + "entity": "mark", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "mark"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoUpdate", + "args": ["camic", "mark"] + } + ] + }, + { + "route": "/data/Mark/types", + "method": "get", + "access": { + "entity": "mark", + "operation": "types" + }, + "handlers": [ + { + "function": "mongoDistinct", + "args": ["camic", "mark", "provenance.analysis"] + } + ] + }, + { + "route": "/data/Mark/multi", + "method": "post", + "access": { + "entity": "mark", + "operation": "multi" + }, + "handlers": [ + { + "function": "markMulti", + "args": [] + } + ] + }, + { + "route": "/data/Mark/spatial", + "method": "get", + "access": { + "entity": "mark", + "operation": "spatial" + }, + "handlers": [ + { + "function": "markSpatial", + "args": [] + } + ] + }, + { + "route": "/data/Mark/findMarkTypes", + "method": "get", + "access": { + "entity": "mark", + "operation": "findMarkTypes" + }, + "handlers": [ + { + "function": "findMarkTypes", + "args": [] + } + ] + }, + { + "route": "/data/Presetlabels/add", + "method": "post", + "access": { + "entity": "presetLabel", + "operation": "create" + }, + "handlers": [ + { + "function": "addPresetlabels", + "args": [] + } + ] + }, + { + "route": "/data/Presetlabels/update", + "method": "post", + "access": { + "entity": "presetLabel", + "operation": "update" + }, + "handlers": [ + { + "function": "updatePresetlabels", + "args": [] + } + ] + }, + { + "route": "/data/Presetlabels/remove", + "method": "post", + "access": { + "entity": "presetLabel", + "operation": "delete" + }, + "handlers": [ + { + "function": "removePresetlabels", + "args": [] + } + ] + }, + { + "route": "/data/Template/find", + "method": "get", + "access": { + "entity": "template", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "template"] + } + ] + }, + { + "route": "/data/Template/post", + "method": "post", + "access": { + "entity": "template", + "operation": "create" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoAdd", + "args": ["camic", "template"] + } + ] + }, + { + "route": "/data/Template/delete", + "method": "delete", + "access": { + "entity": "template", + "operation": "delete" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoDelete", + "args": ["camic", "template"] + } + ] + }, + { + "route": "/data/Template/update", + "method": "post", + "access": { + "entity": "template", + "operation": "update" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin"]] + }, + { + "function": "mongoUpdate", + "args": ["camic", "template"] + } + ] + }, + { + "route": "/data/Heatmap/find", + "method": "get", + "access": { + "entity": "heatmap", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + } + ] + }, + { + "route": "/data/Heatmap/types", + "method": "get", + "access": { + "entity": "heatmap", + "operation": "types" + }, + "handlers": [ + { + "function": "heatmapTypes", + "args": [] + } + ] + }, + { + "route": "/data/Heatmap/post", + "method": "post", + "access": { + "entity": "heatmap", + "operation": "create" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoAdd", + "args": ["camic", "heatmap"] + } + ] + }, + { + "route": "/data/Heatmap/delete", + "method": "delete", + "access": { + "entity": "heatmap", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoDelete", + "args": ["camic", "heatmap"] + } + ] + }, + { + "route": "/data/Heatmap/update", + "method": "post", + "access": { + "entity": "heatmap", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoUpdate", + "args": ["camic", "heatmap"] + } + ] + }, + { + "route": "/data/HeatmapEdit/find", + "method": "get", + "access": { + "entity": "heatmapEdit", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmapEdit"] + } + ] + }, + { + "route": "/data/HeatmapEdit/post", + "method": "post", + "access": { + "entity": "heatmapEdit", + "operation": "create" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoAdd", + "args": ["camic", "heatmapEdit"] + } + ] + }, + { + "route": "/data/HeatmapEdit/delete", + "method": "delete", + "access": { + "entity": "heatmapEdit", + "operation": "delete" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoDelete", + "args": ["camic", "heatmapEdit"] + } + ] + }, + { + "route": "/data/HeatmapEdit/update", + "method": "post", + "access": { + "entity": "heatmapEdit", + "operation": "update" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "heatmap"] + }, + { + "function": "editHandler", + "args": ["data"] + }, + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoUpdate", + "args": ["camic", "heatmapEdit"] + } + ] + }, + { + "route": "/data/Log/find", + "method": "get", + "access": { + "entity": "log", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "log"] + } + ] + }, + { + "route": "/data/Log/post", + "method": "post", + "access": { + "entity": "log", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "log"] + } + ] + }, + { + "route": "/data/Log/delete", + "method": "delete", + "access": { + "entity": "log", + "operation": "delete" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoDelete", + "args": ["camic", "log"] + } + ] + }, + { + "route": "/data/Log/update", + "method": "post", + "access": { + "entity": "log", + "operation": "update" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoUpdate", + "args": ["camic", "log"] + } + ] + }, + { + "route": "/data/Freeform/find", + "method": "get", + "access": { + "entity": "freeform", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "freeform"] + } + ] + }, + { + "route": "/data/Freeform/post", + "method": "post", + "access": { + "entity": "freeform", + "operation": "create" + }, + "handlers": [ + { + "function": "mongoAdd", + "args": ["camic", "freeform"] + } + ] + }, + { + "route": "/data/Freeform/delete", + "method": "delete", + "access": { + "entity": "freeform", + "operation": "delete" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoDelete", + "args": ["camic", "freeform"] + } + ] + }, + { + "route": "/data/Freeform/update", + "method": "post", + "access": { + "entity": "freeform", + "operation": "update" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoUpdate", + "args": ["camic", "freeform"] + } + ] + }, + { + "route": "/data/Configuration/find", + "method": "get", + "access": { + "entity": "configuration", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "configuration"] + } + ] + }, + { + "route": "/data/Configuration/post", + "method": "post", + "access": { + "entity": "configuration", + "operation": "create" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoAdd", + "args": ["camic", "configuration"] + } + ] + }, + { + "route": "/data/Configuration/delete", + "method": "delete", + "access": { + "entity": "configuration", + "operation": "delete" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoDelete", + "args": ["camic", "configuration"] + } + ] + }, + { + "route": "/data/Configuration/update", + "method": "post", + "access": { + "entity": "configuration", + "operation": "update" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoUpdate", + "args": ["camic", "configuration"] + } + ] + }, + { + "route": "/data/Collection/find", + "method": "get", + "access": { + "entity": "collection", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "collection"] + } + ] + }, + { + "route": "/data/Collection/post", + "method": "post", + "access": { + "entity": "collection", + "operation": "create" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoAdd", + "args": ["camic", "collection"] + } + ] + }, + { + "route": "/data/Collection/update", + "method": "post", + "access": { + "entity": "collection", + "operation": "update" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoUpdate", + "args": ["camic", "collection"] + } + ] + }, + { + "route": "/data/Collection/delete", + "method": "delete", + "access": { + "entity": "collection", + "operation": "delete" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "mongoDelete", + "args": ["camic", "collection"] + } + ] + }, + { + "route": "/data/User/find", + "method": "get", + "access": { + "entity": "user", + "operation": "read" + }, + "handlers": [ + { + "function": "mongoFind", + "args": ["camic", "user"] + } + ] + }, + { + "route": "/data/User/post", + "method": "post", + "access": { + "entity": "user", + "operation": "create" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin"]] + }, + { + "function": "mongoAdd", + "args": ["camic", "user"] + } + ] + }, + { + "route": "/data/User/delete", + "method": "delete", + "access": { + "entity": "user", + "operation": "delete" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin"]] + }, + { + "function": "mongoDelete", + "args": ["camic", "user"] + } + ] + }, + { + "route": "/data/User/update", + "method": "post", + "access": { + "entity": "user", + "operation": "update" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin"]] + }, + { + "function": "mongoUpdate", + "args": ["camic", "user"] + } + ] + }, + { + "route": "/data/User/wcido", + "method": "get", + "access": { + "entity": "user", + "operation": "wcido" + }, + "handlers": [ + { + "function": "wcido", + "args": [] + } + ] + }, + { + "route": "/workbench/uploadDataset", + "method": "post", + "access": { + "entity": "workbench", + "operation": "uploadDataset" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "getDataset", + "args": [] + } + ] + }, + { + "route": "/workbench/trainModel", + "method": "post", + "access": { + "entity": "workbench", + "operation": "trainModel" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "trainModel", + "args": [] + } + ] + }, + { + "route": "/workbench/deleteUserData", + "method": "post", + "access": { + "entity": "workbench", + "operation": "deleteUserData" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "deleteDataset", + "args": [] + } + ] + }, + { + "route": "/workbench/modelDownload", + "method": "post", + "access": { + "entity": "workbench", + "operation": "modelDownload" + }, + "handlers": [ + { + "function": "permissionHandler", + "args": [["Admin", "Editor"]] + }, + { + "function": "sendTrainedModel", + "args": [] + } ] } ] diff --git a/service/database/connector.js b/service/database/connector.js index b24d580..0e17277 100644 --- a/service/database/connector.js +++ b/service/database/connector.js @@ -1,4 +1,4 @@ -const { MongoClient } = require("mongodb"); +const { MongoClient } = require('mongodb'); /** * @class MongoDBConnector @@ -15,9 +15,8 @@ class MongoDBConnector { */ constructor() { /** connection specifics */ - const connectionString = - process.env.MONGO_URI || "mongodb://127.0.0.1:27017"; - const databaseName = process.env.MONGO_DB || "camic"; + const connectionString = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017'; + const databaseName = process.env.MONGO_DB || 'camic'; const url = `${connectionString}/${databaseName}`; /** connection configurations */ @@ -48,13 +47,10 @@ const connector = new MongoDBConnector(); * to load connection instances in database operations * @param {string} [databaseName=camic] Returns a connection to the said database */ -const getConnection = (databaseName = "camic") => { - return connector.db[databaseName]; -}; +const getConnection = (databaseName = 'camic') => connector.db[databaseName]; /** export the connector to be used by utility functions */ module.exports = { getConnection, connector, }; - diff --git a/service/database/index.js b/service/database/index.js index 58cb7c8..7ca70ff 100644 --- a/service/database/index.js +++ b/service/database/index.js @@ -1,5 +1,5 @@ -const { getConnection } = require("./connector"); -const { transformIdToObjectId } = require("./util"); +const { getConnection } = require('./connector'); +const { transformIdToObjectId } = require('./util'); /** * @class Mongo @@ -29,8 +29,8 @@ class Mongo { /** allow caller method to toggle response transformation */ if (transform) { data.forEach((x) => { - x["_id"] = { - $oid: x["_id"], + x._id = { + $oid: x._id, }; }); } @@ -154,7 +154,7 @@ class Mongo { filter = transformIdToObjectId(filter); const collection = await getConnection(database).collection( - collectionName + collectionName, ); const result = await collection.updateOne(filter, updates); delete result.connection; diff --git a/service/database/util.js b/service/database/util.js index 3dea949..73666f1 100644 --- a/service/database/util.js +++ b/service/database/util.js @@ -1,4 +1,4 @@ -const { ObjectID } = require("mongodb"); +const { ObjectID } = require('mongodb'); /** * Utility function to transform id from String format to ObjectID format @@ -13,8 +13,8 @@ const { ObjectID } = require("mongodb"); const transformIdToObjectId = (query) => { const payload = { ...query }; try { - if (payload["_id"]) { - payload["_id"] = new ObjectID(payload["_id"]); + if (payload._id) { + payload._id = new ObjectID(payload._id); } return payload; } catch (e) { diff --git a/service/keys/index.js b/service/keys/index.js new file mode 100644 index 0000000..91e4f14 --- /dev/null +++ b/service/keys/index.js @@ -0,0 +1,149 @@ +const fs = require('fs'); +const { execSync } = require('child_process'); +const path = require('path'); +const jwksClient = require('jwks-rsa'); + +/** + * data to append towards the start and end of command + */ +const commands = { + pre: 'openssl req -subj ', + post: ' -x509 -nodes -newkey rsa:2048 -keyout ./keys/key -out ./keys/key.pub', +}; + +/** + * declare location of keys + */ +const location = { + privateKey: path.join(__dirname, '../../keys/key'), + publicKey: path.join(__dirname, '../../keys/key.pub'), +}; + +/** + * load system configurations + */ +const { + GENERATE_KEY_IF_MISSING, ENABLE_SECURITY_AT, DISABLE_SEC, JWK_URL, +} = process.env; +const env = { + DISABLE_SEC: DISABLE_SEC == 'true', + ENABLE_SECURITY_AT: ENABLE_SECURITY_AT || false, + GENERATE_KEY_IF_MISSING: GENERATE_KEY_IF_MISSING == 'true', + JWK_URL, +}; + +/** + * Returns true or false based on three conditions. If security enabled + * timestamp provided, if security is disabled, and if passed timestamp + * has passed or not. + * + * @returns {boolean} whether security is enabled or not in the system + */ +const isSecurityDisabled = () => { + if (!env.ENABLE_SECURITY_AT) { + return false; + } + + if (env.DISABLE_SEC) { + return true; + } + + return Date.parse(ENABLE_SECURITY_AT) > Date.now(); +}; + +/** + * this method will generate the keys if they are missing + * from /keys directory + */ +const generateKeysIfMissing = () => { + /** + * keeping the env as first comparison will skip file operations + * if generation is disabled from configurations. If the file + * operations are kept first, then fs access is performed irrespective + * of application configurations. + * + * This will generate a new config whenever either of the keys are missing + * and the application config allows generation + */ + if ( + env.GENERATE_KEY_IF_MISSING + && (!fs.existsSync(location.privateKey) || !fs.existsSync(location.publicKey)) + ) { + try { + execSync( + `${commands.pre}'/CN=www.camicroscope.com/O=caMicroscope Local Instance Key./C=US'${commands.post}`, + ); + } catch (err) { + console.log({ err }); + } + } +}; + +/** + * this method returns the private key if security rules are in place + */ +const readPrivateKey = () => { + /** if security is disabled, skip all checks and return empty */ + if (isSecurityDisabled()) { + console.warn('private key null, security rules disabled'); + return ''; + } + + try { + if (fs.existsSync(location.privateKey)) { + return fs.readFileSync(location.privateKey, 'utf8'); + } + console.warn('private key does not exist'); + } catch (err) { + console.error(err); + } +}; + +/** + * this method returns the public key if security rules does not exist + */ +const readPublicKey = () => { + /** if security is disabled, skip all checks and return empty */ + if (isSecurityDisabled()) { + console.warn('public key null, security rules disabled'); + return ''; + } + + try { + if (fs.existsSync(location.publicKey)) { + return fs.readFileSync(location.publicKey, 'utf8'); + } + console.warn('private key does not exist'); + } catch (err) { + console.error(err); + } +}; + +/** + * this method provides a JWKS client based on configurations which can be directly + * exported from the auth handler + */ +const getJWKSClient = () => { + if (env.DISABLE_SEC && !env.JWK_URL) { + return jwksClient({ + jwksUri: 'https://www.googleapis.com/oauth2/v3/certs', + }); + } + + if (env.JWK_URL) { + return jwksClient({ + jwksUri: JWK_URL, + }); + } + + console.error('need JWKS URL (JWK_URL)'); + process.exit(1); +}; + +module.exports = { + getJWKSClient, + readPublicKey, + readPrivateKey, + generateKeysIfMissing, + isSecurityDisabled, +}; diff --git a/service/roles/defaultRoles.js b/service/roles/defaultRoles.js new file mode 100644 index 0000000..30d9d76 --- /dev/null +++ b/service/roles/defaultRoles.js @@ -0,0 +1,838 @@ +const defaultRules = [ + { + role: 'visitor', + resource: 'middleware.loader', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'middleware.loader', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'middleware.loader', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'middleware.googleAuth', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'middleware.googleAuth', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'middleware.googleAuth', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'middleware.img', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'middleware.img', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'middleware.img', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'middleware.data', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'middleware.data', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'middleware.data', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'middleware.list', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'middleware.list', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'slide', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'slide', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'slide', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'slide', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'slide', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'slide', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'slide', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'slide', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'slide', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'request', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'request', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'request', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'request', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'request', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'request', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'request', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'mark', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'mark', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'mark', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'mark.types', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'mark.types', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'mark.types', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'mark.multi', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'mark.multi', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'mark.multi', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'mark.spatial', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'mark.spatial', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'mark.spatial', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'mark.findMarkTypes', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'mark.findMarkTypes', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'mark.findMarkTypes', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'mark', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'mark', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'mark', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'mark', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'mark', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'mark', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'presetLabel', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'presetLabel', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'presetLabel', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'presetLabel', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'presetLabel', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'presetLabel', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'presetLabel', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'presetLabel', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'presetLabel', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'template', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'template', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'template', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'template', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'template', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'template', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'template', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'template', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'template', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'heatmap', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'heatmap', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'heatmap', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'heatmap.types', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'heatmap.types', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'heatmap.types', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'heatmap', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'heatmap', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'heatmap', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'heatmap', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'heatmap', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'heatmap', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'heatmapEdit', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'heatmapEdit', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'heatmapEdit', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'heatmapEdit', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'heatmapEdit', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'heatmapEdit', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'heatmapEdit', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'heatmapEdit', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'heatmapEdit', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'log', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'log', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'log', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'log', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'log', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'log', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'log', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'log', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'log', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'log', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'freeform', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'freeform', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'freeform', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'freeform', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'freeform', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'freeform', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'freeform', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'freeform', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'freeform', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'freeform', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'configuration', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'configuration', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'configuration', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'configuration', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'configuration', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'configuration', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'configuration', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'configuration', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'configuration', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'user', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'user', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'user', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'visitor', + resource: 'user.wcido', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'user.wcido', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'user.wcido', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'user', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'user', + action: 'create:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'user', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'user', + action: 'delete:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'user', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'user', + action: 'update:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'workbench.uploadDataset', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'workbench.uploadDataset', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'workbench.trainModel', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'workbench.trainModel', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'workbench.deleteUserData', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'workbench.deleteUserData', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'editor', + resource: 'workbench.modelDownload', + action: 'read:any', + attributes: ['*'], + }, + { + role: 'admin', + resource: 'workbench.modelDownload', + action: 'read:any', + attributes: ['*'], + }, +]; + +module.exports = defaultRules; diff --git a/service/roles/definitions.js b/service/roles/definitions.js new file mode 100644 index 0000000..f411552 --- /dev/null +++ b/service/roles/definitions.js @@ -0,0 +1,184 @@ +const { AccessControl } = require('accesscontrol'); +const { ROLE } = require('./roles'); +const { RESOURCE } = require('./resources'); + +const controller = new AccessControl(); + +/** load peer services */ +const MongoDB = require('../database'); +const DefaultRoles = require('./defaultRoles'); + +/** + * Define the roles to be used in the application by default. These would + * continue to function irrespective of the database state. + */ + +/** Visitor = person without a role, unauthenticated */ +controller + .grant(ROLE.VISITOR) + .read(RESOURCE.MIDDLEWARE('loader.proxyHandler')) + .read(RESOURCE.MIDDLEWARE('googleAuth')) + .read(RESOURCE.MIDDLEWARE('img.iip.raw')) + .read(RESOURCE.MIDDLEWARE('data')) + .read(RESOURCE.SLIDE()) + .create(RESOURCE.REQUEST()) + .read(RESOURCE.MARK()) + .read(RESOURCE.MARK('types')) + .read(RESOURCE.MARK('multi')) + .read(RESOURCE.MARK('spatial')) + .read(RESOURCE.MARK('findMarkTypes')) + .create(RESOURCE.PRESET_LABEL()) + .update(RESOURCE.PRESET_LABEL()) + .delete(RESOURCE.PRESET_LABEL()) + .read(RESOURCE.TEMPLATE()) + .read(RESOURCE.HEATMAP()) + .read(RESOURCE.HEATMAP('types')) + .read(RESOURCE.HEATMAP_EDIT()) + .read(RESOURCE.LOG()) + .create(RESOURCE.LOG()) + .read(RESOURCE.FREEFORM()) + .create(RESOURCE.FREEFORM()) + .read(RESOURCE.CONFIGURATION()) + .read(RESOURCE.USER()) + .read(RESOURCE.USER('wcido')); + +/** + * The role definitions can be extended. For example here, the role EDITOR + * extends the role VISITOR. This means that whatever rights are granted to + * the role VISITOR, they will also be granted to the role EDITOR. + * + * When editing the roles in the GUI editor, the same rule is applied to the + * role definitions. + */ +controller + .grant(ROLE.EDITOR) + .extend(ROLE.VISITOR) + .read(RESOURCE.MIDDLEWARE('loader.login')) + .read(RESOURCE.MIDDLEWARE('loader.slide.delete')) + .read(RESOURCE.MIDDLEWARE('list')) + .create(RESOURCE.SLIDE()) + .delete(RESOURCE.SLIDE()) + .update(RESOURCE.SLIDE()) + .read(RESOURCE.REQUEST()) + .delete(RESOURCE.REQUEST()) + .create(RESOURCE.MARK()) + .update(RESOURCE.MARK()) + .delete(RESOURCE.MARK()) + .create(RESOURCE.TEMPLATE()) + .update(RESOURCE.TEMPLATE()) + .delete(RESOURCE.TEMPLATE()) + .create(RESOURCE.HEATMAP()) + .update(RESOURCE.HEATMAP()) + .delete(RESOURCE.HEATMAP()) + .create(RESOURCE.HEATMAP_EDIT()) + .update(RESOURCE.HEATMAP_EDIT()) + .delete(RESOURCE.HEATMAP_EDIT()) + .delete(RESOURCE.LOG()) + .update(RESOURCE.LOG()) + .update(RESOURCE.FREEFORM()) + .delete(RESOURCE.FREEFORM()) + .create(RESOURCE.CONFIGURATION()) + .delete(RESOURCE.CONFIGURATION()) + .update(RESOURCE.CONFIGURATION()) + .create(RESOURCE.USER()) + .delete(RESOURCE.USER()) + .update(RESOURCE.USER()) + .read(RESOURCE.WORKBENCH('uploadDataset')) + .read(RESOURCE.WORKBENCH('trainModel')) + .read(RESOURCE.WORKBENCH('deleteUserData')) + .read(RESOURCE.WORKBENCH('modelDownload')); + +/** roles of moderator in system */ +controller.grant(ROLE.ADMIN).extend(ROLE.EDITOR); + +/** + * @global + * livehandler contains the current access control instance. This can change + * midway in the application when the roles are updated from the GUI editor. + * + * Whenever the rules are changed, the liveHandle is updated and the + * getAccessControlHandle starts to point to the new liveHandle. + */ +let liveHandle = controller; + +/** + * function to return the latest instance of the access control + * @return {AccessControl} + */ +const getAccessControlHandle = () => liveHandle; + +/** + * This method initializes the access control and assigns the live handle to + * the global variable. This ensures that whenever the instance is to used, + * it will be the latest instance and all operations would be consistent. + */ +const initialize = async () => { + /** load the roles from the database */ + const roles = await MongoDB.find('camic', 'roles', {}); + + /** + * if roles are not found, then save the default connfiguration into the + * database. This allows the application to start with a default role + * hard-coded from the code-base, and then depend + */ + if (roles.length === 0) { + /** + * @todo :- dynamically generate the default roles from controller + * currently its loaded from the statis file. + */ + const insertOperation = await MongoDB.add('camic', 'roles', DefaultRoles); + console.log( + `[service:roles] Created default roles: ${insertOperation.insertedIds}`, + ); + } else { + console.log( + `[service:roles] Found ${roles.length} entries in the database`, + ); + } + + /** + * initialize an instance of the access control with the loaded roles + * from the database. + */ + liveHandle = new AccessControl(roles); +}; + +const updateRules = async (rules) => { + /** update the access control with the new rules */ + liveHandle = new AccessControl(rules); + + try { + await MongoDB.delete('camic', 'roles', {}); + console.log('[service:roles] roles cleared:'); + const insertOperation = await MongoDB.add('camic', 'roles', rules); + console.log('[service:roles] roles inserted:', insertOperation.length); + + return true; + } catch (e) { + console.error('[service:roles] roles insert failed:', e); + return false; + } +}; + +/** + * Method to display the details about the access control instance during + * application bootstrapping. + * + * This runs after the database is initialized, and tries to display the + * access control instance state after the database rules import. + */ +const roleStatusCheck = () => { + console.log('[service:roles] roles:', liveHandle.getRoles()); + console.log( + '[service:roles] resources:', + JSON.stringify(liveHandle.getResources()), + ); +}; + +module.exports = { + check: controller, + roleStatusCheck, + initializeRolesService: initialize, + getAccessControlHandle, + updateRules, +}; diff --git a/service/roles/middleware.js b/service/roles/middleware.js new file mode 100644 index 0000000..18965c9 --- /dev/null +++ b/service/roles/middleware.js @@ -0,0 +1,103 @@ +/** + * This file contains the middleware that implements the role checks in the appplication + */ +// const routes = require('../../routes.json'); + +/** + * Loading other services + * + * roles/roles => to summon all types of roles into the system + * + */ +const { DEFAULT_ROLE } = require('./roles'); +const { getAccessControlHandle } = require('./definitions'); + +/** + * This middleware parses the incoming request for user role details and decides whether + * or not to allow the user. + * + * Flow: + * - Incoming User Request with auth headers + * - Auth headers checked for role definitions + * - If no role found, default role assigned + * - Checked for role definitions in ./definitions.js + * - Pass or Fail user + * @function + * @param {string} route route to attach the role checking service to + * @param {{entity:string, operation:string}} access access identifier to identify resource + */ +const RoleProcessor = (route, access) => { + const middleware = (req, res, next) => { + /** get latest instance of the access control handle on every request */ + const check = getAccessControlHandle(); + + /** express middleware definition */ + console.log('----------------------------------------'); + console.log(`user type : ${req.userType}`); + console.log('----------------------------------------'); + + let userRole = DEFAULT_ROLE; + + /** check if the incoming request contains a user role */ + if (req.userType) { + userRole = req.userType; + } + + /** destruct data from access */ + const { entity, operation } = access; + + /** check if the incoming request is allowed to access or not */ + switch (operation) { + /** check for write/create writes */ + case 'create': + if (!check.can(userRole).create(entity)) { + return res + .status(403) + .send(`You are not allowed to create ${entity}`); + } + break; + + /** check for read rights */ + case 'read': + if (!check.can(userRole).read(entity)) { + return res.status(403).send(`You are not allowed to read ${entity}`); + } + break; + + /** check for update rights */ + case 'update': + if (!check.can(userRole).update(entity)) { + return res + .status(403) + .send(`You are not allowed to update ${entity}`); + } + break; + + /** check for delete rights */ + case 'delete': + if (!check.can(userRole).delete(entity)) { + return res + .status(403) + .send(`You are not allowed to delete ${entity}`); + } + break; + + default: + /** check if a custom operation type is used + * if so, then we check the custom operation + */ + if (!check.can(userRole).read(`${entity}.${operation}`)) { + return res + .status(403) + .send(`You are not allowed to operate on ${entity}.${operation}`); + } + break; + } + + return next(); + }; + + return middleware; +}; + +module.exports = { RoleProcessor }; diff --git a/service/roles/resources.js b/service/roles/resources.js new file mode 100644 index 0000000..79e1640 --- /dev/null +++ b/service/roles/resources.js @@ -0,0 +1,33 @@ +/** + * Helper function to allow using sub sections in the resource types. + * which are strictly not defined as resource types. + * + * This allows quickly adding new routes / resources to operate in the application. + * + * @param {string} head => the name of the resource + * @param {string} tail => the sub section of the resource apart from basic CRUD + */ +const fx = (head, tail) => `${head}${tail ? `.${tail}` : ''}`; + +/** + * RESOURCE represents various entities that are operated in the application. + * This object is used to define role definitions with a consistent style + */ +const RESOURCE = { + LOG: (x) => fx('log', x), + USER: (x) => fx('user', x), + MARK: (x) => fx('mark', x), + SLIDE: (x) => fx('slide', x), + HEATMAP: (x) => fx('heatmap', x), + REQUEST: (x) => fx('request', x), + FREEFORM: (x) => fx('freeform', x), + TEMPLATE: (x) => fx('template', x), + WORKBENCH: (x) => fx('workbench', x), + COLLECTION: (x) => fx('collection', x), + MIDDLEWARE: (x) => fx('middleware', x), + PRESET_LABEL: (x) => fx('presetLabel', x), + HEATMAP_EDIT: (x) => fx('heatmapEdit', x), + CONFIGURATION: (x) => fx('configuration', x), +}; + +module.exports = { RESOURCE }; diff --git a/service/roles/roles.js b/service/roles/roles.js new file mode 100644 index 0000000..4b50130 --- /dev/null +++ b/service/roles/roles.js @@ -0,0 +1,15 @@ +/** + * This file defines the roles in system in the form of an object. + * + * These are expected to be used throughout the application in place of direct strings + */ + +const ROLE = { + ADMIN: 'admin', + EDITOR: 'editor', + VISITOR: 'visitor', +}; + +const DEFAULT_ROLE = ROLE.VISITOR; + +module.exports = { ROLE, DEFAULT_ROLE }; diff --git a/service/roles/routes.js b/service/roles/routes.js new file mode 100644 index 0000000..6d042d3 --- /dev/null +++ b/service/roles/routes.js @@ -0,0 +1,27 @@ +/** load express instance to declare routes */ +const express = require('express'); + +const router = express.Router(); + +/** + * load peer dependencies + */ +const { getAccessControlHandle, updateRules } = require('./definitions'); + +router.get('/', (req, res) => { + const instance = getAccessControlHandle(); + return res.json(instance.getGrants()); +}); + +router.post('/', async (req, res) => { + const payload = JSON.parse(req.body); + const updateOperation = await updateRules(payload); + + if (updateOperation === true) { + return res.json({ success: true }); + } + + return res.json({ success: false }); +}); + +module.exports = { roleRoutes: router }; diff --git a/service/routes/entityAndOperations.js b/service/routes/entityAndOperations.js new file mode 100644 index 0000000..75fd26e --- /dev/null +++ b/service/routes/entityAndOperations.js @@ -0,0 +1,32 @@ +const fs = require('fs'); +const path = require('path'); +/** + * Returns all the entities defined in the application + * along with the operations. + */ +const listEntityAndOperations = async () => { + const rawData = await fs.readFileSync( + path.join(__dirname, '../../routes.json'), + ); + const data = JSON.parse(rawData); + + const entityList = {}; + + /** + * for each entry in routes.json, find all possible operations + */ + data.forEach((entry) => { + if (entry.access !== undefined) { + if (!Object.keys(entityList).includes(entry.access.entity)) { + entityList[entry.access.entity] = []; + } + + entityList[entry.access.entity].push(entry.access.operation); + } + }); + + console.log(JSON.stringify(entityList)); + return entityList; +}; +listEntityAndOperations(); +module.exports = { listEntityAndOperations }; diff --git a/validator.js b/service/routes/validator.js similarity index 59% rename from validator.js rename to service/routes/validator.js index 59ccab7..ccaef01 100644 --- a/validator.js +++ b/service/routes/validator.js @@ -1,9 +1,11 @@ -const Ajv = require("ajv"); +const Ajv = require('ajv'); +const path = require('path'); + const ajv = new Ajv(); -require("ajv-keywords")(ajv); +require('ajv-keywords')(ajv); /** loading dataset */ -const routeDefinitions = require("./routes.json"); +const routeDefinitions = require('../../routes.json'); /** * Quick information about schema declaration @@ -18,21 +20,21 @@ const routeDefinitions = require("./routes.json"); /** declare schema */ const schema = { - type: "array", + type: 'array', items: { - type: "object", + type: 'object', oneOf: [ /** static blocks */ { properties: { method: { - const: "static", + const: 'static', }, use: { - type: "string", + type: 'string', }, }, - required: ["method", "use"], + required: ['method', 'use'], }, /** use middleware */ @@ -40,36 +42,49 @@ const schema = { properties: { /** the type of requests which are accepted by the entry */ method: { - enum: ["use", "get", "post", "delete"], + enum: ['use', 'get', 'post', 'delete'], }, /** the URL fragment on which the route is attached */ route: { - type: "string", + type: 'string', + }, + + /** information related to access rights of the item */ + access: { + type: 'object', + properties: { + /** the category to which the operation belongs */ + entity: { type: 'string' }, + + /** slug to identify the operation */ + operation: { type: 'string' }, + }, + required: ['entity', 'operation'], }, /** list of handlers / middleware layers attached to given route */ handlers: { /** each route has multiple handles attached to it, therefore array */ - type: "array", + type: 'array', items: { - type: "object", + type: 'object', properties: { /** the name of the function that is attached from the codebase to the route */ - function: { type: "string" }, + function: { type: 'string' }, /** array of arguments that are passed into the above specified function */ args: { - type: "array", + type: 'array', }, }, - required: ["function", "args"], + required: ['function', 'args'], }, }, }, - required: ["method", "route", "handlers"], + required: ['method', 'route', 'handlers', 'access'], }, ], }, @@ -79,4 +94,4 @@ const schema = { const validate = ajv.compile(schema); const valid = validate(routeDefinitions); -valid === true ? console.log("ok") : console.log(validate.errors); +valid === true ? console.log('ok') : console.log(validate.errors); diff --git a/test/functional/slide_lifecycle.js b/test/functional/slide_lifecycle.js index 6403d46..e426b0f 100644 --- a/test/functional/slide_lifecycle.js +++ b/test/functional/slide_lifecycle.js @@ -3,57 +3,58 @@ const chaiHttp = require('chai-http'); const server = require('../../caracal.js'); -var should = chai.should(); +const should = chai.should(); chai.use(chaiHttp); - const posturl = '/data/Slide/post'; const findurl = '/data/Slide/find'; const deleteurl = '/data/Slide/delete'; process.env.DISABLE_SEC = 'true'; -describe('Slide Lifecycle Step 1', function() { - it('Posts a Slide', function(done) { +describe('Slide Lifecycle Step 1', () => { + it('Posts a Slide', function (done) { this.timeout(5000); - var slideData = {'name': 'TEST', 'specimen': '', 'study': '', 'location': '/images/sample.svs', 'mpp': 0.499}; + const slideData = { + name: 'TEST', specimen: '', study: '', location: '/images/sample.svs', mpp: 0.499, + }; chai.request(server) - .post(posturl) - .set('Content-Type', 'application/json; charset=utf-8') - .send(slideData) - .end(function(err, res) { - (res).should.have.status(200); - (res.body).should.be.a('object'); - (res.body.insertedCount).should.be.eql(1); - done(); - }); + .post(posturl) + .set('Content-Type', 'application/json; charset=utf-8') + .send(slideData) + .end((err, res) => { + (res).should.have.status(200); + (res.body).should.be.a('object'); + (res.body.insertedCount).should.be.eql(1); + done(); + }); }); }); -describe('Slide Lifecycle Step 2', function() { - it('Finds the Slide', function(done) { +describe('Slide Lifecycle Step 2', () => { + it('Finds the Slide', function (done) { this.timeout(5000); chai.request(server) - .get(findurl + '?name=TEST') - .set('Content-Type', 'application/json; charset=utf-8') - .end(function(err, res) { - (res).should.have.status(200); - (res.body).should.be.an('array'); - (res.body.length).should.be.eql(1); - done(); - }); + .get(`${findurl}?name=TEST`) + .set('Content-Type', 'application/json; charset=utf-8') + .end((err, res) => { + (res).should.have.status(200); + (res.body).should.be.an('array'); + (res.body.length).should.be.eql(1); + done(); + }); }); }); -describe('Slide Lifecycle Step 3', function() { - it('Deletes a Slide', function(done) { +describe('Slide Lifecycle Step 3', () => { + it('Deletes a Slide', function (done) { this.timeout(5000); chai.request(server) - .delete(deleteurl + '?name=TEST') - .set('Content-Type', 'application/json; charset=utf-8') - .end(function(err, res) { - (res).should.have.status(200); - (res.body).should.be.a('object'); - (res.body.result.n).should.be.eql(1); - done(); - }); + .delete(`${deleteurl}?name=TEST`) + .set('Content-Type', 'application/json; charset=utf-8') + .end((err, res) => { + (res).should.have.status(200); + (res.body).should.be.a('object'); + (res.body.result.n).should.be.eql(1); + done(); + }); }); }); diff --git a/test/unit/authHandlers.js b/test/unit/authHandlers.js index cd1f702..2d2b10d 100644 --- a/test/unit/authHandlers.js +++ b/test/unit/authHandlers.js @@ -1,36 +1,37 @@ const chai = require('chai'); -var auth = require('../../handlers/authHandlers.js'); -var should = chai.should(); +const auth = require('../../handlers/authHandlers.js'); + +const should = chai.should(); process.env.DISABLE_SEC = 'true'; -describe('filterHandler', function() { - it('Filters on a given field', function(done) { - var req = {}; - var res = {}; +describe('filterHandler', () => { + it('Filters on a given field', function (done) { + const req = {}; + const res = {}; req.filter = ['LOW_SEC']; req.data = [ - {'name': 'public'}, - {'name': 'low security', 'filter': 'LOW_SEC'}, - {'name': 'high security', 'filter': 'HIGH_SEC'}, + { name: 'public' }, + { name: 'low security', filter: 'LOW_SEC' }, + { name: 'high security', filter: 'HIGH_SEC' }, ]; this.timeout(5000); - auth.filterHandler('data', 'filter', 'filter')(req, res, function() {}); + auth.filterHandler('data', 'filter', 'filter')(req, res, () => {}); (req.data).should.be.an('array'); (req.data.length).should.be.eql(2); done(); }); - it('Returns all for special command **', function(done) { - var req = {}; - var res = {}; + it('Returns all for special command **', function (done) { + const req = {}; + const res = {}; req.filter = ['**']; req.data = [ - {'name': 'public'}, - {'name': 'low security', 'filter': 'LOW_SEC'}, - {'name': 'high security', 'filter': 'HIGH_SEC'}, + { name: 'public' }, + { name: 'low security', filter: 'LOW_SEC' }, + { name: 'high security', filter: 'HIGH_SEC' }, ]; this.timeout(5000); - auth.filterHandler('data', 'filter', 'filter')(req, res, function() {}); + auth.filterHandler('data', 'filter', 'filter')(req, res, () => {}); (req.data).should.be.an('array'); (req.data.length).should.be.eql(3); done(); diff --git a/test/unit/database.js b/test/unit/database.js index 88157ea..a505496 100644 --- a/test/unit/database.js +++ b/test/unit/database.js @@ -1,13 +1,15 @@ -const chai = require("chai"); -const {ObjectID} = require("mongodb"); -var should = chai.should(); +/* global it */ +const chai = require('chai'); +const { ObjectID } = require('mongodb'); + +const should = chai.should(); const { getConnection, connector, -} = require("./../../service/database/connector"); -const MongoDB = require("./../../service/database/index"); -const Util = require("./../../service/database/util"); +} = require('../../service/database/connector'); +const MongoDB = require('../../service/database/index'); +const Util = require('../../service/database/util'); /** * The services are designed to operate as independent units and therefore by @@ -15,130 +17,129 @@ const Util = require("./../../service/database/util"); * development and debugging without touching the application codebase. */ const DB = { - NAME: "camic", - COLLECTION: "users", + NAME: 'camic', + COLLECTION: 'users', }; /** * all tests for service/database */ -describe("service/database", () => { +describe('service/database', () => { /** wait for connection before initiating tests */ before(async () => { - const connection = () => - new Promise((resolve) => { - connector - .init() - .then(() => { - resolve(true); - }) - .catch(() => { - console.error("Error connecting to database"); - }); - }); + const connection = () => new Promise((resolve) => { + connector + .init() + .then(() => { + resolve(true); + }) + .catch(() => { + console.error('Error connecting to database'); + }); + }); await connection(); }); /** test suite for connector */ - describe("connector", () => { - it("should be defined and callable", () => { + describe('connector', () => { + it('should be defined and callable', () => { getConnection.should.not.be.undefined; - (typeof getConnection).should.equal("function"); + (typeof getConnection).should.equal('function'); }); - it("should return a valid connection when no argument provided", () => { + it('should return a valid connection when no argument provided', () => { const connection = getConnection(); connection.should.not.be.undefined; }); - it("should return a valid connection when database name provided", () => { - const connection = getConnection("camic"); + it('should return a valid connection when database name provided', () => { + const connection = getConnection('camic'); connection.should.not.be.undefined; connection.serverConfig.should.not.be.undefined; }); - it("should inject configuration objects", () => { - const connection = getConnection("camic"); + it('should inject configuration objects', () => { + const connection = getConnection('camic'); connection.serverConfig.s.options.useUnifiedTopology.should.be.true; }); }); /** test suite for utility functions */ - describe("util", () => { - it("should be defined and callable", () => { + describe('util', () => { + it('should be defined and callable', () => { Util.should.not.be.undefined; Util.transformIdToObjectId.should.not.be.undefined; - (typeof Util.transformIdToObjectId).should.equal("function"); + (typeof Util.transformIdToObjectId).should.equal('function'); }); - it("should not alter argument if property _id not exist", () => { + it('should not alter argument if property _id not exist', () => { const original = { - something: "awesome", - repo: "caracal", + something: 'awesome', + repo: 'caracal', valid: true, version: 1, - string: "F", + string: 'F', }; const processed = Util.transformIdToObjectId(original); processed.should.eql(processed); }); - it("should not alter original object passed into function", () => { + it('should not alter original object passed into function', () => { const original = { - foo: "bar", + foo: 'bar', number: 1, - _id: "507f1f77bcf86cd799439011", + _id: '507f1f77bcf86cd799439011', }; const processed = Util.transformIdToObjectId(original); - (typeof original._id).should.be.equal("string"); - (typeof processed._id).should.be.equal("object"); + (typeof original._id).should.be.equal('string'); + (typeof processed._id).should.be.equal('object'); }); - it("should alter datatype of property with valid _id", () => { + it('should alter datatype of property with valid _id', () => { const original = { - foo: "bar", + foo: 'bar', number: 1, - _id: "507f1f77bcf86cd799439011", + _id: '507f1f77bcf86cd799439011', }; - (typeof original._id).should.be.equal("string"); + (typeof original._id).should.be.equal('string'); const processed = Util.transformIdToObjectId(original); - (typeof processed._id).should.be.equal("object"); + (typeof processed._id).should.be.equal('object'); }); - it("should not break if datatype of id not a valid ObjectID", () => { + it('should not break if datatype of id not a valid ObjectID', () => { const original = { - foo: "bar", + foo: 'bar', number: 1, - _id: "507f1_invalid_6cd799439011", + _id: '507f1_invalid_6cd799439011', }; - (typeof original._id).should.be.equal("string"); + (typeof original._id).should.be.equal('string'); const processed = Util.transformIdToObjectId(original); - (typeof processed._id).should.be.equal("string"); + (typeof processed._id).should.be.equal('string'); }); }); /** test suite for core functionality */ - describe("service", () => { + describe('service', () => { /** dummy payload for unit tests */ const USERS = [ { _id: new ObjectID(), - name: "user 1", + name: 'user 1', age: 20, config: { - foo: "bar", + foo: 'bar', }, }, { _id: new ObjectID(), - name: "user 2", + name: 'user 2', age: 20, config: { - foo: "bar", + foo: 'bar', }, }, ]; @@ -150,38 +151,38 @@ describe("service/database", () => { /** clear database after each unit */ afterEach(async () => { - await getConnection().collection(DB.COLLECTION).deleteMany({age: 20}); + await getConnection().collection(DB.COLLECTION).deleteMany({ age: 20 }); await getConnection() - .collection(DB.COLLECTION) - .deleteMany({for: "aggregate"}); + .collection(DB.COLLECTION) + .deleteMany({ for: 'aggregate' }); }); /** ensures that service always provides all database functionality */ - it("should be defined and callable", () => { + it('should be defined and callable', () => { MongoDB.should.not.be.undefined; - (typeof MongoDB).should.be.equal("object"); - (typeof MongoDB.add).should.be.equal("function"); - (typeof MongoDB.aggregate).should.be.equal("function"); - (typeof MongoDB.delete).should.be.equal("function"); - (typeof MongoDB.distinct).should.be.equal("function"); - (typeof MongoDB.find).should.be.equal("function"); - (typeof MongoDB.update).should.be.equal("function"); + (typeof MongoDB).should.be.equal('object'); + (typeof MongoDB.add).should.be.equal('function'); + (typeof MongoDB.aggregate).should.be.equal('function'); + (typeof MongoDB.delete).should.be.equal('function'); + (typeof MongoDB.distinct).should.be.equal('function'); + (typeof MongoDB.find).should.be.equal('function'); + (typeof MongoDB.update).should.be.equal('function'); }); - describe(".add", () => { + describe('.add', () => { /** if it's callable, it means it's defined. */ - it("should be defined and callable", () => { - (typeof MongoDB.add).should.be.equal("function"); + it('should be defined and callable', () => { + (typeof MongoDB.add).should.be.equal('function'); }); /** normal insert operations for single document */ - it("should insert single document into collection", async () => { + it('should insert single document into collection', async () => { const user = { _id: new ObjectID(), - name: "testUser1", + name: 'testUser1', age: 20, config: { - foo: "bar", + foo: 'bar', }, }; @@ -191,22 +192,22 @@ describe("service/database", () => { }); /** should */ - it("should insert multiple document into collection", async () => { + it('should insert multiple document into collection', async () => { const users = [ { _id: new ObjectID(), - name: "testUser1", + name: 'testUser1', age: 20, config: { - foo: "bar", + foo: 'bar', }, }, { _id: new ObjectID(), - name: "testUser2", + name: 'testUser2', age: 20, config: { - foo: "bar", + foo: 'bar', }, }, ]; @@ -221,13 +222,13 @@ describe("service/database", () => { * @todo: unit tests for following methods * .aggregate() */ - describe(".delete", () => { + describe('.delete', () => { /** if its callable, means its defined */ - it("should be defined and callable", () => { - (typeof MongoDB.delete).should.be.equal("function"); + it('should be defined and callable', () => { + (typeof MongoDB.delete).should.be.equal('function'); }); - it("should delete a single document by id", async () => { + it('should delete a single document by id', async () => { const res = await MongoDB.delete(DB.NAME, DB.COLLECTION, { _id: USERS[0]._id, }); @@ -235,7 +236,7 @@ describe("service/database", () => { res.deletedCount.should.be.equal(1); }); - it("should only delete one document even if filter matches many", async () => { + it('should only delete one document even if filter matches many', async () => { const res = await MongoDB.delete(DB.NAME, DB.COLLECTION, { age: 20, }); @@ -243,7 +244,7 @@ describe("service/database", () => { res.deletedCount.should.be.equal(1); }); - it("should not throw error if filter returns empty data", async () => { + it('should not throw error if filter returns empty data', async () => { const res = await MongoDB.delete(DB.NAME, DB.COLLECTION, { age: 50, }); @@ -252,23 +253,23 @@ describe("service/database", () => { }); }); - describe(".find", () => { + describe('.find', () => { /** if its callable, means its defined */ - it("should be defined and callable", () => { - (typeof MongoDB.find).should.be.equal("function"); + it('should be defined and callable', () => { + (typeof MongoDB.find).should.be.equal('function'); }); - it("should list all data when empty filter provided", async () => { + it('should list all data when empty filter provided', async () => { const result = await MongoDB.find(DB.NAME, DB.COLLECTION, {}); result.length.should.be.equal(2); }); - it("should list all data matching given filter", async () => { - const result = await MongoDB.find(DB.NAME, DB.COLLECTION, {age: 20}); + it('should list all data matching given filter', async () => { + const result = await MongoDB.find(DB.NAME, DB.COLLECTION, { age: 20 }); result.length.should.be.equal(2); }); - it("should list specific document when filtered via unique id", async () => { + it('should list specific document when filtered via unique id', async () => { const result = await MongoDB.find(DB.NAME, DB.COLLECTION, { _id: USERS[0]._id, }); @@ -276,110 +277,110 @@ describe("service/database", () => { result[0].name.should.equal(USERS[0].name); }); - it("should return empty array if no data matches given filter", async () => { - const result = await MongoDB.find(DB.NAME, DB.COLLECTION, {age: 21}); + it('should return empty array if no data matches given filter', async () => { + const result = await MongoDB.find(DB.NAME, DB.COLLECTION, { age: 21 }); result.length.should.be.equal(0); }); }); - describe(".update", () => { - it("should be defined and callable", () => { - (typeof MongoDB.update).should.be.equal("function"); + describe('.update', () => { + it('should be defined and callable', () => { + (typeof MongoDB.update).should.be.equal('function'); }); - it("should update a single document even when filter matches multiple items", async () => { + it('should update a single document even when filter matches multiple items', async () => { const res = await MongoDB.update( - DB.NAME, - DB.COLLECTION, - {age: 20}, - { - $set: {name: "new name"}, - }, + DB.NAME, + DB.COLLECTION, + { age: 20 }, + { + $set: { name: 'new name' }, + }, ); res.modifiedCount.should.equal(1); res.matchedCount.should.equal(1); }); - it("should not update any document when filters do not match any document", async () => { + it('should not update any document when filters do not match any document', async () => { const res = await MongoDB.update( - DB.NAME, - DB.COLLECTION, - {age: 50}, - { - $set: {name: "new name"}, - }, + DB.NAME, + DB.COLLECTION, + { age: 50 }, + { + $set: { name: 'new name' }, + }, ); res.modifiedCount.should.equal(0); res.matchedCount.should.equal(0); }); }); - describe(".distinct", () => { - it("should be defined and callable", () => { - (typeof MongoDB.distinct).should.be.equal("function"); + describe('.distinct', () => { + it('should be defined and callable', () => { + (typeof MongoDB.distinct).should.be.equal('function'); }); - it("should return array of distinct values of passed filter", async () => { - const res = await MongoDB.distinct(DB.NAME, DB.COLLECTION, "age", {}); + it('should return array of distinct values of passed filter', async () => { + const res = await MongoDB.distinct(DB.NAME, DB.COLLECTION, 'age', {}); res.length.should.be.equal(1); res[0].should.be.equal(20); }); - it("should return all elements if none repeated in passed filter", async () => { - const res = await MongoDB.distinct(DB.NAME, DB.COLLECTION, "name", {}); + it('should return all elements if none repeated in passed filter', async () => { + const res = await MongoDB.distinct(DB.NAME, DB.COLLECTION, 'name', {}); res.length.should.be.equal(2); }); }); - describe(".aggregate", () => { - it("should be defined and callable", () => { - (typeof MongoDB.aggregate).should.be.equal("function"); + describe('.aggregate', () => { + it('should be defined and callable', () => { + (typeof MongoDB.aggregate).should.be.equal('function'); }); - it("should run a function pipeline on data", async () => { + it('should run a function pipeline on data', async () => { await MongoDB.add(DB.NAME, DB.COLLECTION, [ { _id: new ObjectID(), - name: "user 1", - type: "a", - by: "bot", + name: 'user 1', + type: 'a', + by: 'bot', price: 10, - for: "aggregate", + for: 'aggregate', }, { _id: new ObjectID(), - name: "user 2", - type: "a", - by: "bot", + name: 'user 2', + type: 'a', + by: 'bot', price: 20, - for: "aggregate", + for: 'aggregate', }, { _id: new ObjectID(), - name: "user 3", - type: "b", - by: "human", + name: 'user 3', + type: 'b', + by: 'human', price: 30, - for: "aggregate", + for: 'aggregate', }, { _id: new ObjectID(), - name: "user 4", - type: "b", - by: "human", + name: 'user 4', + type: 'b', + by: 'human', price: 40, - for: "aggregate", + for: 'aggregate', }, ]); const res = await MongoDB.aggregate(DB.NAME, DB.COLLECTION, [ - {$match: {type: "a"}}, - {$group: {_id: "$by", total: {$sum: "$price"}}}, - {$sort: {total: -1}}, + { $match: { type: 'a' } }, + { $group: { _id: '$by', total: { $sum: '$price' } } }, + { $sort: { total: -1 } }, ]); res.length.should.be.equal(1); - res[0]._id.should.be.equal("bot"); + res[0]._id.should.be.equal('bot'); }); }); }); diff --git a/test/unit/permissionHandler.js b/test/unit/permissionHandler.js index e9b72c6..2ece90d 100644 --- a/test/unit/permissionHandler.js +++ b/test/unit/permissionHandler.js @@ -1,24 +1,36 @@ +/* eslint-disable no-unused-vars */ + const chai = require('chai'); -var permissionHandler = require('../../handlers/permssionHandler.js'); -var should = chai.should(); +const { describe, it } = require('mocha'); +const should = chai.should(); + +/** + * loading services + * + * roles => to summon all defined roles in the system + * permissionHandler => to defined permission rules on resources + */ +const { ROLE } = require('../../service/roles/roles'); +const permissionHandler = require('../../handlers/permssionHandler'); -describe('permissionHandler', function() { - it('Accepts if ok', function(done) { - var req = {}; - var res = {}; - req.tokenInfo = {'userType': 'nice'}; +describe('permissionHandler', () => { + it('should accept if OK', (done) => { + const req = {}; + const res = {}; + req.tokenInfo = { userType: ROLE.ADMIN }; this.timeout(5000); - permissionHandler(['nice'], true)(req, res, function() {}); - (req.permission_ok).should.be.eql(true); + permissionHandler([ROLE.ADMIN], true)(req, res, () => {}); + req.permission_ok.should.be.eql(true); done(); }); - it('Rejects if not', function(done) { - var req = {}; - var res = {}; - req.tokenInfo = {'userType': 'naughty'}; + + it('should reject if not OK', (done) => { + const req = {}; + const res = {}; + req.tokenInfo = { userType: ROLE.VISITOR }; this.timeout(5000); - permissionHandler(['nice'], true)(req, res, function() {}); - (req.permission_ok).should.be.eql(false); + permissionHandler([ROLE.ADMIN], true)(req, res, () => {}); + req.permission_ok.should.be.eql(false); done(); }); }); diff --git a/test/unit/roles.js b/test/unit/roles.js new file mode 100644 index 0000000..d938819 --- /dev/null +++ b/test/unit/roles.js @@ -0,0 +1,301 @@ +/* eslint-disable no-unused-vars */ +/* eslint-disable no-unused-expressions */ +/* eslint-disable no-undef */ +const { expect } = require('chai'); +const { describe, it, before, beforeEach } = require('mocha'); +/** + * The services are designed to operate as independent units and therefore by + * design, must not depend / interfere with the main codebase. This allows + * development and debugging without touching the application codebase. + */ +const DB = { + NAME: 'camic', + COLLECTION: 'roles', +}; + +/** + * load dependencies to test + */ +const { AccessControl } = require('accesscontrol'); +const MongoDB = require('../../service/database'); +const { + connector, + getConnection, +} = require('../../service/database/connector'); +const { + getAccessControlHandle, + initializeRolesService, + roleStatusCheck, + updateRules, +} = require('../../service/roles/definitions'); +const { RoleProcessor } = require('../../service/roles/middleware'); +const { DEFAULT_ROLE, ROLE } = require('../../service/roles/roles'); +const { RESOURCE } = require('../../service/roles/resources'); +const { roleRoutes } = require('../../service/roles/routes'); + +/** + * all tests for service/database + */ +describe('service/roles', () => { + /** ensure database is live before testing */ + before(async () => { + const connection = () => + new Promise((resolve) => { + connector + .init() + .then(() => { + resolve(true); + }) + .catch(() => { + console.error('Error connecting to database'); + }); + }); + await connection(); + }); + + /** definitions.js test suite */ + describe('/definititons', () => { + describe('getAccessControlHandle', () => { + // should be defined + it('should be defined', () => { + expect(getAccessControlHandle).not.to.be.undefined; + }); + + // should return a function + it('should return a function', () => { + expect(getAccessControlHandle).to.be.a('function'); + }); + + // should return an instance of AccessControl + it('should return an instance of AccessControl', () => { + const returnValue = getAccessControlHandle(); + expect(returnValue).to.be.an.instanceof(AccessControl); + }); + + // should not return an undefined value + it('should not return an undefined value', () => { + const returnValue = getAccessControlHandle(); + expect(returnValue).to.not.be.undefined; + }); + }); + + describe('roleStatusCheck', () => { + // should be defined + it('should be defined', () => { + expect(roleStatusCheck).not.to.be.undefined; + }); + + // should be callable + it('should be callable', () => { + expect(roleStatusCheck).to.be.a('function'); + }); + }); + + describe('initializeRolesService', () => { + /** delete the roles collection before each test */ + beforeEach(async () => { + const collection = getConnection(DB.NAME).collection(DB.COLLECTION); + await collection.deleteMany({}); + }); + + // roles collection should become empty before test + it('[env] roles collection should become empty before test', async () => { + // get all documents from roles collection + const allDocumments = await MongoDB.find('camic', 'roles', {}); + expect(allDocumments).to.be.empty; + }); + + // should be defined + it('should be defined', () => { + expect(initializeRolesService).not.to.be.undefined; + }); + + // should be a function + it('should be a function', () => { + expect(initializeRolesService).to.be.a('function'); + }); + + // should seed the database with default rows when no rows exist + it('should seed the database when no rows exist', async () => { + // get all documents from roles collection + const allDocuments = await MongoDB.find('camic', 'roles', {}); + expect(allDocuments).to.be.empty; + + // seed the roles collection with default rows + await initializeRolesService(); + + // get all documents from roles collection + const allDocumentsAfterInit = await MongoDB.find('camic', 'roles', {}); + expect(allDocumentsAfterInit).to.not.be.empty; + }); + + // should not seed the database when rows already exist + it('should not seed the database when rows already exist', async () => { + const allDocuments = await MongoDB.find('camic', 'roles', {}); + expect(allDocuments).to.be.empty; + + // insert a document to simulate existing data + const insertOperation = await MongoDB.add('camic', 'roles', [ + { + role: 'visitor', + resource: 'middleware.loader', + action: 'read:any', + attributes: ['*'], + }, + ]); + expect(insertOperation.result.n).to.equal(1); + + // ensure that the read operation reflects the changes + const allDocumentsAfterSampleInsert = await MongoDB.find( + 'camic', + 'roles', + {}, + ); + expect(allDocumentsAfterSampleInsert.length).to.equal(1); + + // now initialize the roles service + await initializeRolesService(); + + // ensure that initializing the roles service did not change anything + const allDocumentsAfterInit = await MongoDB.find('camic', 'roles', {}); + expect(allDocumentsAfterInit.length).to.be.equal(1); + }); + }); + + describe('updateRules', () => { + // should be defined + it('should be defined', () => { + expect(updateRules).not.to.be.undefined; + }); + + // should be a function + it('should be a function', () => { + expect(updateRules).to.be.a('function'); + }); + + // should update the latest instance as per new rules + it('should update the latest instance as per new rules', async () => { + // get the default access control handle + const accessControlHandle = getAccessControlHandle(); + + // ensure that the default handle has rules + expect(accessControlHandle.getGrants()).to.not.be.empty; + + // now update the instance by passing new rules into updateRule + const newRules = [ + { + role: 'admin', + resource: 'video', + action: 'create:any', + attributes: '*, !views', + }, + { + role: 'admin', + resource: 'video', + action: 'read:any', + attributes: '*', + }, + { + role: 'admin', + resource: 'video', + action: 'update:any', + attributes: '*, !views', + }, + { + role: 'admin', + resource: 'video', + action: 'delete:any', + attributes: '*', + }, + ]; + + // update the rules + await updateRules(newRules); + + // get the latest instance of access control handle + const latestAccessControlHandle = getAccessControlHandle(); + + // ensure that the latest instance has new rules + expect(latestAccessControlHandle.getGrants()).to.not.be.empty; + + // ensure that the two instances are not the same + expect(latestAccessControlHandle.getRoles()).to.not.equal( + accessControlHandle.getRoles(), + ); + expect(latestAccessControlHandle.getResources()).to.not.equal( + accessControlHandle.getResources(), + ); + expect(latestAccessControlHandle.getGrants()).to.not.equal( + accessControlHandle.getGrants(), + ); + }); + }); + }); + + /** middleware test suite */ + describe('/middleware', () => { + // should be defined + it('should be defined', () => { + expect(RoleProcessor).not.to.be.undefined; + }); + + // should be callable + it('should be callable', () => { + expect(RoleProcessor).to.be.a('function'); + }); + + // shuld return a function + it('should return a function', () => { + expect(RoleProcessor()).to.be.a('function'); + }); + }); + + describe('/ROLE', () => { + // should be defined + it('should be defined', () => { + expect(ROLE).not.to.be.undefined; + }); + + // should be an object + it('should be an object', () => { + expect(ROLE).to.be.an('object'); + }); + + // should have a default role + it('should have a default role', () => { + expect(DEFAULT_ROLE).not.to.be.undefined; + }); + + // should be a string + it('should be a string', () => { + expect(DEFAULT_ROLE).to.be.a('string'); + }); + }); + + describe('/resource', () => { + // should be defined + it('should be defined', () => { + expect(RESOURCE).not.to.be.undefined; + }); + + // should be an object + it('should be an object', () => { + expect(RESOURCE).to.be.an('object'); + }); + + // properties should be functions + it('all properties should be functions', () => { + const keys = Object.keys(RESOURCE); + keys.forEach((key) => { + expect(RESOURCE[key]).to.be.a('function'); + }); + }); + }); + + describe('/roleRoutes', () => { + // should be defined + it('should be defined', () => { + expect(roleRoutes).not.to.be.undefined; + }); + }); +});