diff --git a/.circleci/config.yml b/.circleci/config.yml index 4eb7fa3c..a2f85016 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ version: 2 defaults: &defaults - docker: - - image: cimg/python:3.11.0-browsers + docker: + - image: cimg/python:3.11.0-browsers install_dependency: &install_dependency name: Installation of build and deployment dependencies. command: | @@ -13,7 +13,7 @@ install_dependency: &install_dependency install_deploysuite: &install_deploysuite name: Installation of install_deploysuite. command: | - git clone --branch v1.4 https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript + git clone --branch v1.4.14 https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript cp ./../buildscript/master_deploy.sh . cp ./../buildscript/buildenv.sh . cp ./../buildscript/awsconfiguration.sh . @@ -23,60 +23,77 @@ restore_cache_settings_for_build: &restore_cache_settings_for_build save_cache_settings: &save_cache_settings key: docker-node-modules-{{ checksum "yarn.lock" }} paths: - - node_modules + - node_modules builddeploy_steps: &builddeploy_steps - - checkout - - setup_remote_docker - - run: *install_dependency - - run: *install_deploysuite - - restore_cache: *restore_cache_settings_for_build - - run: ./build.sh ${APPNAME} - - save_cache: *save_cache_settings - - deploy: - name: Running MasterScript. - command: | - ./awsconfiguration.sh $DEPLOY_ENV - source awsenvconf - ./buildenv.sh -e $DEPLOY_ENV -b ${LOGICAL_ENV}-${APPNAME}-deployvar - source buildenvvar - ./master_deploy.sh -d ECS -e $DEPLOY_ENV -t latest -s ${LOGICAL_ENV}-global-appvar,${LOGICAL_ENV}-${APPNAME}-appvar -i ${APPNAME} - - +- checkout +- setup_remote_docker +- run: *install_dependency +- run: *install_deploysuite +- restore_cache: *restore_cache_settings_for_build +- run: + name: "Authenticate with CodeArtifact and build docker image" + command: "./awsconfiguration.sh ${CODEARTIFACT_ENV}\nsource awsenvconf\naws codeartifact login --tool npm --repository topcoder-framework --domain topcoder --domain-owner $AWS_ACCOUNT_ID --region $AWS_REGION --namespace @topcoder-framework\ncp ~/.npmrc .\nrm -f awsenvconf \n./build.sh ${APPNAME}\n" +- save_cache: *save_cache_settings +- deploy: + name: Running MasterScript. + command: | + ./awsconfiguration.sh $DEPLOY_ENV + source awsenvconf + ./buildenv.sh -e $DEPLOY_ENV -b ${LOGICAL_ENV}-${APPNAME}-deployvar + source buildenvvar + ./master_deploy.sh -d ECS -e $DEPLOY_ENV -t latest -s ${LOGICAL_ENV}-global-appvar,${LOGICAL_ENV}-${APPNAME}-appvar -i ${APPNAME} jobs: # Build & Deploy against development backend "build-dev": - <<: *defaults + !!merge <<: *defaults environment: DEPLOY_ENV: "DEV" LOGICAL_ENV: "dev" - APPNAME: "challenge-api" + APPNAME: "challenge-api" + CODEARTIFACT_ENV: "PROD" + steps: *builddeploy_steps + + "build-qa": + !!merge <<: *defaults + environment: + DEPLOY_ENV: "QA" + LOGICAL_ENV: "qa" + APPNAME: "challenge-api" + CODEARTIFACT_ENV: "PROD" steps: *builddeploy_steps "build-prod": - <<: *defaults + !!merge <<: *defaults environment: DEPLOY_ENV: "PROD" - LOGICAL_ENV: "prod" - APPNAME: "challenge-api" + LOGICAL_ENV: "prod" + APPNAME: "challenge-api" steps: *builddeploy_steps workflows: version: 2 build: jobs: - # Development builds are executed on "develop" branch only. - - "build-dev": - context : org-global - filters: - branches: - only: - - dev + # Development builds are executed on "develop" branch only. + - "build-dev": + context: org-global + filters: + branches: + only: + - dev + + - "build-qa": + context: org-global + filters: + branches: + only: + - refactor/domain-challenge - # Production builds are exectuted only on tagged commits to the - # master branch. - - "build-prod": - context : org-global - filters: - branches: - only: master \ No newline at end of file + # Production builds are exectuted only on tagged commits to the + # master branch. + - "build-prod": + context: org-global + filters: + branches: + only: master diff --git a/.gitignore b/.gitignore index 493bab5b..9d35fdf0 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ logs npm-debug.log* yarn-debug.log* yarn-error.log* +.yarn # Runtime data pids @@ -60,4 +61,5 @@ typings/ # next.js build output .next +ecr-login.sh .npmrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..2e47837e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "printWidth": 100 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 1f6a871c..4b667af1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,6 @@ { - "editor.defaultFormatter": "standard.vscode-standard", - "standard.autoFixOnSave": true -} \ No newline at end of file + "standard.autoFixOnSave": true, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/README.md b/README.md index ca02c8a4..99e51234 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,6 @@ The following parameters can be set in config files or in env variables: - ES.HOST: Elasticsearch host - ES.API_VERSION: Elasticsearch API version - ES.ES_INDEX: Elasticsearch index name -- ES.ES_TYPE: Elasticsearch index type - ES.ES_REFRESH: Elasticsearch refresh method. Default to string `true`(i.e. refresh immediately) - FILE_UPLOAD_SIZE_LIMIT: the file upload size limit in bytes - RESOURCES_API_URL: TC resources API base URL diff --git a/app-bootstrap.js b/app-bootstrap.js index 6792c5f7..4516ae56 100644 --- a/app-bootstrap.js +++ b/app-bootstrap.js @@ -1,11 +1,11 @@ /** * App bootstrap */ -global.Promise = require('bluebird') -const Joi = require('joi') +global.Promise = require("bluebird"); +const Joi = require("joi"); -Joi.optionalId = () => Joi.string().uuid() -Joi.id = () => Joi.optionalId().required() -Joi.page = () => Joi.number().integer().min(1).default(1) -Joi.perPage = () => Joi.number().integer().min(1).max(100).default(20) -Joi.fileSize = () => Joi.number().integer().min(0).default(0) +Joi.optionalId = () => Joi.string().uuid(); +Joi.id = () => Joi.optionalId().required(); +Joi.page = () => Joi.number().integer().min(1).default(1); +Joi.perPage = () => Joi.number().integer().min(1).max(100).default(20); +Joi.fileSize = () => Joi.number().integer().min(0).default(0); diff --git a/app-constants.js b/app-constants.js index 7cad4648..17ec44d8 100644 --- a/app-constants.js +++ b/app-constants.js @@ -1,135 +1,138 @@ -const config = require('config') +const config = require("config"); /** * App constants */ const UserRoles = { - Admin: 'administrator', - Copilot: 'copilot', - Manager: 'Connect Manager', - User: 'Topcoder User', - SelfServiceCustomer: 'Self-Service Customer' -} + Admin: "administrator", + Copilot: "copilot", + Manager: "Connect Manager", + User: "Topcoder User", + SelfServiceCustomer: "Self-Service Customer", +}; const prizeSetTypes = { - ChallengePrizes: 'placement', - CopilotPayment: 'copilot', - ReviewerPayment: 'reviewer', - CheckpointPrizes: 'checkpoint' -} + ChallengePrizes: "placement", + CopilotPayment: "copilot", + ReviewerPayment: "reviewer", + CheckpointPrizes: "checkpoint", +}; const challengeStatuses = { - New: 'New', - Draft: 'Draft', - Approved: 'Approved', - Cancelled: 'Cancelled', - Active: 'Active', - Completed: 'Completed', - Deleted: 'Deleted', - CancelledFailedReview: 'Cancelled - Failed Review', - CancelledFailedScreening: 'Cancelled - Failed Screening', - CancelledZeroSubmissions: 'Cancelled - Zero Submissions', - CancelledWinnerUnresponsive: 'Cancelled - Winner Unresponsive', - CancelledClientRequest: 'Cancelled - Client Request', - CancelledRequirementsInfeasible: 'Cancelled - Requirements Infeasible', - CancelledZeroRegistrations: 'Cancelled - Zero Registrations', - CancelledPaymentFailed: 'Cancelled - Payment Failed' -} + New: "New", + Draft: "Draft", + Approved: "Approved", + Cancelled: "Cancelled", + Active: "Active", + Completed: "Completed", + Deleted: "Deleted", + CancelledFailedReview: "Cancelled - Failed Review", + CancelledFailedScreening: "Cancelled - Failed Screening", + CancelledZeroSubmissions: "Cancelled - Zero Submissions", + CancelledWinnerUnresponsive: "Cancelled - Winner Unresponsive", + CancelledClientRequest: "Cancelled - Client Request", + CancelledRequirementsInfeasible: "Cancelled - Requirements Infeasible", + CancelledZeroRegistrations: "Cancelled - Zero Registrations", + CancelledPaymentFailed: "Cancelled - Payment Failed", +}; const validChallengeParams = { - UpdatedBy: 'updatedBy', - Updated: 'updated', - CreatedBy: 'createdBy', - Created: 'created', - EndDate: 'endDate', - StartDate: 'startDate', - ProjectId: 'projectId', - Name: 'name', - Type: 'type', - NumOfSubmissions: 'numOfSubmissions', - NumOfRegistrants: 'numOfRegistrants', - Status: 'status', - TypeId: 'typeId', - Prizes: 'overview.totalPrizes' -} + UpdatedBy: "updatedBy", + Updated: "updated", + CreatedBy: "createdBy", + Created: "created", + EndDate: "endDate", + StartDate: "startDate", + ProjectId: "projectId", + Name: "name", + Type: "type", + NumOfSubmissions: "numOfSubmissions", + NumOfRegistrants: "numOfRegistrants", + Status: "status", + TypeId: "typeId", + Prizes: "overview.totalPrizes", +}; -const EVENT_ORIGINATOR = 'topcoder-challenges-api' +const EVENT_ORIGINATOR = "topcoder-challenges-api"; -const EVENT_MIME_TYPE = 'application/json' +const EVENT_MIME_TYPE = "application/json"; const DiscussionTypes = { - Challenge: 'challenge' -} + Challenge: "challenge", +}; // using a testing topc, should be changed to use real topics in comments when they are created const Topics = { - ChallengeCreated: 'challenge.notification.create', - ChallengeUpdated: 'challenge.notification.update', - ChallengeDeleted: 'challenge.notification.delete', - ChallengeTypeCreated: 'test.new.bus.events', // 'challenge.action.type.created', - ChallengeTypeUpdated: 'test.new.bus.events', // 'challenge.action.type.updated', - ChallengeTypeDeleted: 'test.new.bus.events', // 'challenge.action.type.deleted', - ChallengeTrackCreated: 'test.new.bus.events', // 'challenge.action.track.created', - ChallengeTrackUpdated: 'test.new.bus.events', // 'challenge.action.track.updated', - ChallengeTrackDeleted: 'test.new.bus.events', // 'challenge.action.track.deleted', - ChallengePhaseCreated: 'test.new.bus.events', // 'challenge.action.phase.created', - ChallengePhaseUpdated: 'test.new.bus.events', // 'challenge.action.phase.updated', - ChallengePhaseDeleted: 'test.new.bus.events', // 'challenge.action.phase.deleted', - TimelineTemplateCreated: 'test.new.bus.events', // 'challenge.action.timeline.template.created', - TimelineTemplateUpdated: 'test.new.bus.events', // 'challenge.action.timeline.template.updated', - TimelineTemplateDeleted: 'test.new.bus.events', // 'challenge.action.timeline.template.deleted', - ChallengeTypeTimelineTemplateCreated: 'test.new.bus.events', // 'challenge.action.type.timeline.template.created', - ChallengeTypeTimelineTemplateUpdated: 'test.new.bus.events', // 'challenge.action.type.timeline.template.updated', - ChallengeTypeTimelineTemplateDeleted: 'test.new.bus.events', // 'challenge.action.type.timeline.template.deleted' - ChallengeAttachmentCreated: 'test.new.bus.events', // 'challenge.action.attachment.created', - ChallengeAttachmentUpdated: 'test.new.bus.events', // 'challenge.action.attachment.updated', - ChallengeAttachmentDeleted: 'test.new.bus.events', // 'challenge.action.attachment.deleted', + ChallengeCreated: "challenge.notification.create", + ChallengeUpdated: "challenge.notification.update", + ChallengeDeleted: "challenge.notification.delete", + ChallengeTypeCreated: "test.new.bus.events", // 'challenge.action.type.created', + ChallengeTypeUpdated: "test.new.bus.events", // 'challenge.action.type.updated', + ChallengeTypeDeleted: "test.new.bus.events", // 'challenge.action.type.deleted', + ChallengeTrackCreated: "test.new.bus.events", // 'challenge.action.track.created', + ChallengeTrackUpdated: "test.new.bus.events", // 'challenge.action.track.updated', + ChallengeTrackDeleted: "test.new.bus.events", // 'challenge.action.track.deleted', + ChallengePhaseCreated: "test.new.bus.events", // 'challenge.action.phase.created', + ChallengePhaseUpdated: "test.new.bus.events", // 'challenge.action.phase.updated', + ChallengePhaseDeleted: "test.new.bus.events", // 'challenge.action.phase.deleted', + TimelineTemplateCreated: "test.new.bus.events", // 'challenge.action.timeline.template.created', + TimelineTemplateUpdated: "test.new.bus.events", // 'challenge.action.timeline.template.updated', + TimelineTemplateDeleted: "test.new.bus.events", // 'challenge.action.timeline.template.deleted', + ChallengeTypeTimelineTemplateCreated: "test.new.bus.events", // 'challenge.action.type.timeline.template.created', + ChallengeTypeTimelineTemplateUpdated: "test.new.bus.events", // 'challenge.action.type.timeline.template.updated', + ChallengeTypeTimelineTemplateDeleted: "test.new.bus.events", // 'challenge.action.type.timeline.template.deleted' + ChallengeAttachmentCreated: "test.new.bus.events", // 'challenge.action.attachment.created', + ChallengeAttachmentUpdated: "test.new.bus.events", // 'challenge.action.attachment.updated', + ChallengeAttachmentDeleted: "test.new.bus.events", // 'challenge.action.attachment.deleted', + ChallengeTimelineTemplateCreated: "challenge.action.challenge.timeline.created", + ChallengeTimelineTemplateUpdated: "challenge.action.challenge.timeline.updated", + ChallengeTimelineTemplateDeleted: "challenge.action.challenge.timeline.deleted", // Self Service topics - Notifications: 'notifications.action.create' -} + Notifications: "notifications.action.create", +}; const challengeTracks = { - DEVELOP: 'DEVELOP', - DESIGN: 'DESIGN', - DATA_SCIENCE: 'DATA_SCIENCE', - QA: 'QA' -} + DEVELOP: "DEVELOP", + DESIGN: "DESIGN", + DATA_SCIENCE: "DATA_SCIENCE", + QA: "QA", +}; const challengeTextSortField = { - Name: 'name', - TypeId: 'typeId' -} + Name: "name", + TypeId: "typeId", +}; const reviewTypes = { - Community: 'COMMUNITY', - Internal: 'INTERNAL' -} + Community: "COMMUNITY", + Internal: "INTERNAL", +}; const SelfServiceNotificationTypes = { - WORK_REQUEST_SUBMITTED: 'self-service.notifications.work-request-submitted', - WORK_REQUEST_STARTED: 'self-service.notifications.work-request-started', - WORK_REQUEST_REDIRECTED: 'self-service.notifications.work-request-redirected', - WORK_COMPLETED: 'self-service.notifications.work-completed' -} + WORK_REQUEST_SUBMITTED: "self-service.notifications.work-request-submitted", + WORK_REQUEST_STARTED: "self-service.notifications.work-request-started", + WORK_REQUEST_REDIRECTED: "self-service.notifications.work-request-redirected", + WORK_COMPLETED: "self-service.notifications.work-completed", +}; const SelfServiceNotificationSettings = { [SelfServiceNotificationTypes.WORK_REQUEST_SUBMITTED]: { sendgridTemplateId: config.SENDGRID_TEMPLATES.WORK_REQUEST_SUBMITTED, - cc: [] + cc: [], }, [SelfServiceNotificationTypes.WORK_REQUEST_STARTED]: { sendgridTemplateId: config.SENDGRID_TEMPLATES.WORK_REQUEST_STARTED, - cc: [] + cc: [], }, [SelfServiceNotificationTypes.WORK_REQUEST_REDIRECTED]: { sendgridTemplateId: config.SENDGRID_TEMPLATES.WORK_REQUEST_REDIRECTED, - cc: [...config.SELF_SERVICE_EMAIL_CC_ACCOUNTS] + cc: [...config.SELF_SERVICE_EMAIL_CC_ACCOUNTS], }, [SelfServiceNotificationTypes.WORK_COMPLETED]: { sendgridTemplateId: config.SENDGRID_TEMPLATES.WORK_COMPLETED, - cc: [] - } -} + cc: [], + }, +}; module.exports = { UserRoles, @@ -144,5 +147,5 @@ module.exports = { DiscussionTypes, reviewTypes, SelfServiceNotificationTypes, - SelfServiceNotificationSettings -} + SelfServiceNotificationSettings, +}; diff --git a/app-routes.js b/app-routes.js index a77b491d..3632e13e 100644 --- a/app-routes.js +++ b/app-routes.js @@ -2,13 +2,13 @@ * Configure all routes for express app */ -const _ = require('lodash') -const config = require('config') -const HttpStatus = require('http-status-codes') -const helper = require('./src/common/helper') -const errors = require('./src/common/errors') -const routes = require('./src/routes') -const authenticator = require('tc-core-library-js').middleware.jwtAuthenticator +const _ = require("lodash"); +const config = require("config"); +const HttpStatus = require("http-status-codes"); +const helper = require("./src/common/helper"); +const errors = require("./src/common/errors"); +const routes = require("./src/routes"); +const authenticator = require("tc-core-library-js").middleware.jwtAuthenticator; /** * Configure all routes for express app @@ -18,97 +18,108 @@ module.exports = (app) => { // Load all routes _.each(routes, (verbs, path) => { _.each(verbs, (def, verb) => { - const controllerPath = `./src/controllers/${def.controller}` + const controllerPath = `./src/controllers/${def.controller}`; const method = require(controllerPath)[def.method]; // eslint-disable-line if (!method) { - throw new Error(`${def.method} is undefined`) + throw new Error(`${def.method} is undefined`); } - const actions = [] + const actions = []; actions.push((req, res, next) => { - req.signature = `${def.controller}#${def.method}` - next() - }) + req.signature = `${def.controller}#${def.method}`; + next(); + }); actions.push((req, res, next) => { - if (_.get(req, 'query.token')) { - _.set(req, 'headers.authorization', `Bearer ${_.trim(req.query.token)}`) + if (_.get(req, "query.token")) { + _.set(req, "headers.authorization", `Bearer ${_.trim(req.query.token)}`); } - next() - }) + next(); + }); if (def.auth) { // add Authenticator/Authorization check if route has auth actions.push((req, res, next) => { - authenticator(_.pick(config, ['AUTH_SECRET', 'VALID_ISSUERS']))(req, res, next) - }) + authenticator(_.pick(config, ["AUTH_SECRET", "VALID_ISSUERS"]))(req, res, next); + }); actions.push((req, res, next) => { if (req.authUser.isMachine) { // M2M if (!req.authUser.scopes || !helper.checkIfExists(def.scopes, req.authUser.scopes)) { - next(new errors.ForbiddenError('You are not allowed to perform this action!')) + next(new errors.ForbiddenError("You are not allowed to perform this action!")); } else { - req.authUser.handle = config.M2M_AUDIT_HANDLE - req.userToken = req.headers.authorization.split(' ')[1] - next() + req.authUser.handle = config.M2M_AUDIT_HANDLE; + req.authUser.userId = config.M2M_AUDIT_USERID; + req.userToken = req.headers.authorization.split(" ")[1]; + next(); } } else { - req.authUser.userId = String(req.authUser.userId) + req.authUser.userId = String(req.authUser.userId); // User roles authorization if (req.authUser.roles) { - if (def.access && !helper.checkIfExists(_.map(def.access, a => a.toLowerCase()), _.map(req.authUser.roles, r => r.toLowerCase()))) { - next(new errors.ForbiddenError('You are not allowed to perform this action!')) + if ( + def.access && + !helper.checkIfExists( + _.map(def.access, (a) => a.toLowerCase()), + _.map(req.authUser.roles, (r) => r.toLowerCase()) + ) + ) { + next(new errors.ForbiddenError("You are not allowed to perform this action!")); } else { // user token is used in create/update challenge to ensure user can create/update challenge under specific project - req.userToken = req.headers.authorization.split(' ')[1] - next() + req.userToken = req.headers.authorization.split(" ")[1]; + next(); } } else { - next(new errors.ForbiddenError('You are not authorized to perform this action')) + next(new errors.ForbiddenError("You are not authorized to perform this action")); } } - }) + }); } else { // public API, but still try to authenticate token if provided, but allow missing/invalid token actions.push((req, res, next) => { - const interceptRes = {} - interceptRes.status = () => interceptRes - interceptRes.json = () => interceptRes - interceptRes.send = () => next() - authenticator(_.pick(config, ['AUTH_SECRET', 'VALID_ISSUERS']))(req, interceptRes, next) - }) + const interceptRes = {}; + interceptRes.status = () => interceptRes; + interceptRes.json = () => interceptRes; + interceptRes.send = () => next(); + authenticator(_.pick(config, ["AUTH_SECRET", "VALID_ISSUERS"]))(req, interceptRes, next); + }); actions.push((req, res, next) => { if (!req.authUser) { - next() + next(); } else if (req.authUser.isMachine) { - if (!def.scopes || !req.authUser.scopes || !helper.checkIfExists(def.scopes, req.authUser.scopes)) { - req.authUser = undefined + if ( + !def.scopes || + !req.authUser.scopes || + !helper.checkIfExists(def.scopes, req.authUser.scopes) + ) { + req.authUser = undefined; } - next() + next(); } else { - req.authUser.userId = String(req.authUser.userId) - next() + req.authUser.userId = String(req.authUser.userId); + next(); } - }) + }); } - actions.push(method) - app[verb](`/${config.API_VERSION}${path}`, helper.autoWrapExpress(actions)) - }) - }) + actions.push(method); + app[verb](`/${config.API_VERSION}${path}`, helper.autoWrapExpress(actions)); + }); + }); // Check if the route is not found or HTTP method is not supported - app.use('*', (req, res) => { + app.use("*", (req, res) => { if (routes[req.baseUrl]) { res.status(HttpStatus.METHOD_NOT_ALLOWED).json({ - message: 'The requested HTTP method is not supported.' - }) + message: "The requested HTTP method is not supported.", + }); } else { res.status(HttpStatus.NOT_FOUND).json({ - message: 'The requested resource cannot be found.' - }) + message: "The requested resource cannot be found.", + }); } - }) -} + }); +}; diff --git a/app.js b/app.js index 7f98945e..72bc3362 100644 --- a/app.js +++ b/app.js @@ -2,120 +2,136 @@ * The application entry point */ -require('./app-bootstrap') - -const _ = require('lodash') -const config = require('config') -const express = require('express') -const bodyParser = require('body-parser') -const cors = require('cors') -const HttpStatus = require('http-status-codes') -const logger = require('./src/common/logger') -const interceptor = require('express-interceptor') -const fileUpload = require('express-fileupload') -const YAML = require('yamljs') -const swaggerUi = require('swagger-ui-express') -const challengeAPISwaggerDoc = YAML.load('./docs/swagger.yaml') -const { ForbiddenError } = require('./src/common/errors') +require("./app-bootstrap"); + +const _ = require("lodash"); +const config = require("config"); +const express = require("express"); +const bodyParser = require("body-parser"); +const cors = require("cors"); +const HttpStatus = require("http-status-codes"); +const logger = require("./src/common/logger"); +const interceptor = require("express-interceptor"); +const fileUpload = require("express-fileupload"); +const YAML = require("yamljs"); +const swaggerUi = require("swagger-ui-express"); +const challengeAPISwaggerDoc = YAML.load("./docs/swagger.yaml"); +const { ForbiddenError } = require("./src/common/errors"); // setup express app -const app = express() +const app = express(); // Disable POST, PUT, PATCH, DELETE operations if READONLY is set to true app.use((req, res, next) => { - if (config.READONLY === true && ['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) { - throw new ForbiddenError('Action is temporarely not allowed!') + if (config.READONLY === true && ["POST", "PUT", "PATCH", "DELETE"].includes(req.method)) { + throw new ForbiddenError("Action is temporarely not allowed!"); } - next() -}) + next(); +}); // serve challenge V5 API swagger definition -app.use('/v5/challenges/docs', swaggerUi.serve, swaggerUi.setup(challengeAPISwaggerDoc)) - -app.use(cors({ - exposedHeaders: [ - 'X-Prev-Page', - 'X-Next-Page', - 'X-Page', - 'X-Per-Page', - 'X-Total', - 'X-Total-Pages', - 'Link' - ] -})) -app.use(fileUpload({ - limits: { fileSize: config.FILE_UPLOAD_SIZE_LIMIT } -})) -app.use(bodyParser.json()) -app.use(bodyParser.urlencoded({ extended: true })) -app.set('port', config.PORT) +app.use("/v5/challenges/docs", swaggerUi.serve, swaggerUi.setup(challengeAPISwaggerDoc)); + +app.use( + cors({ + exposedHeaders: [ + "X-Prev-Page", + "X-Next-Page", + "X-Page", + "X-Per-Page", + "X-Total", + "X-Total-Pages", + "Link", + ], + }) +); +app.use( + fileUpload({ + limits: { fileSize: config.FILE_UPLOAD_SIZE_LIMIT }, + }) +); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); +app.set("port", config.PORT); // intercept the response body from jwtAuthenticator -app.use(interceptor((req, res) => { - return { - isInterceptable: () => { - return res.statusCode === 403 - }, - - intercept: (body, send) => { - let obj - try { - obj = JSON.parse(body) - } catch (e) { - logger.error('Invalid response body.') - } - if (obj && obj.result && obj.result.content && obj.result.content.message) { - const ret = { message: obj.result.content.message } - res.statusCode = 401 - send(JSON.stringify(ret)) - } else { - send(body) - } - } - } -})) +app.use( + interceptor((req, res) => { + return { + isInterceptable: () => { + return res.statusCode === 403; + }, + + intercept: (body, send) => { + let obj; + try { + obj = JSON.parse(body); + } catch (e) { + logger.error("Invalid response body."); + } + if (obj && obj.result && obj.result.content && obj.result.content.message) { + const ret = { message: obj.result.content.message }; + res.statusCode = 401; + send(JSON.stringify(ret)); + } else { + send(body); + } + }, + }; + }) +); // Register routes -require('./app-routes')(app) +require("./app-routes")(app); // The error handler // eslint-disable-next-line no-unused-vars app.use((err, req, res, next) => { - logger.logFullError(err, req.signature || `${req.method} ${req.url}`) - const errorResponse = {} - const status = err.isJoi ? HttpStatus.BAD_REQUEST : (err.httpStatus || _.get(err, 'response.status') || HttpStatus.INTERNAL_SERVER_ERROR) + logger.logFullError(err, req.signature || `${req.method} ${req.url}`); + const errorResponse = {}; + let status = err.isJoi + ? HttpStatus.BAD_REQUEST + : err.httpStatus || _.get(err, "response.status") || HttpStatus.INTERNAL_SERVER_ERROR; + + // Check if err is a GrpcError + if (err.details != null && err.code != null) { + status = err.code == 5 ? HttpStatus.NOT_FOUND : HttpStatus.BAD_REQUEST; // TODO: Use @topcoder-framework/lib-common to map GrpcError codes to HTTP codes + errorResponse.code = err.code; + errorResponse.message = err.details; + } if (_.isArray(err.details)) { if (err.isJoi) { _.map(err.details, (e) => { if (e.message) { if (_.isUndefined(errorResponse.message)) { - errorResponse.message = e.message + errorResponse.message = e.message; } else { - errorResponse.message += `, ${e.message}` + errorResponse.message += `, ${e.message}`; } } - }) + }); } } - if (_.get(err, 'response.status')) { + if (_.get(err, "response.status")) { // extra error message from axios http response(v4 and v5 tc api) - errorResponse.message = _.get(err, 'response.data.result.content.message') || _.get(err, 'response.data.message') + errorResponse.message = + _.get(err, "response.data.result.content.message") || _.get(err, "response.data.message"); } if (_.isUndefined(errorResponse.message)) { if (err.message && status !== HttpStatus.INTERNAL_SERVER_ERROR) { - errorResponse.message = err.message + errorResponse.message = err.message; } else { - errorResponse.message = 'Internal server error' + errorResponse.message = "Internal server error"; } } - res.status(status).json(errorResponse) -}) + res.status(status).json(errorResponse); +}); -app.listen(app.get('port'), () => { - logger.info(`Express server listening on port ${app.get('port')}`) -}) +app.listen(app.get("port"), () => { + logger.info(`Express server listening on port ${app.get("port")}`); +}); -module.exports = app +module.exports = app; diff --git a/config/default.js b/config/default.js index 70c0d29f..3c4f0045 100644 --- a/config/default.js +++ b/config/default.js @@ -1,112 +1,131 @@ /** * The configuration file. */ -const _ = require('lodash') -require('dotenv').config() +const _ = require("lodash"); +require("dotenv").config(); module.exports = { - READONLY: process.env.READONLY === 'true' || false, - LOG_LEVEL: process.env.LOG_LEVEL || 'debug', + READONLY: process.env.READONLY === "true" || false, + LOG_LEVEL: process.env.LOG_LEVEL || "debug", PORT: process.env.PORT || 3000, // used to properly set the header response to api calls for services behind a load balancer API_BASE_URL: process.env.API_BASE_URL || `http://localhost:3000`, - API_VERSION: process.env.API_VERSION || 'v5', - AUTH_SECRET: process.env.AUTH_SECRET || 'mysecret', - VALID_ISSUERS: process.env.VALID_ISSUERS || '["https://api.topcoder-dev.com", "https://api.topcoder.com", "https://topcoder-dev.auth0.com/"]', + API_VERSION: process.env.API_VERSION || "v5", + AUTH_SECRET: process.env.AUTH_SECRET || "mysecret", + VALID_ISSUERS: + process.env.VALID_ISSUERS || + '["https://api.topcoder-dev.com", "https://api.topcoder.com", "https://topcoder-dev.auth0.com/"]', // used to get M2M token AUTH0_URL: process.env.AUTH0_URL, AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL, - AUTH0_AUDIENCE: process.env.AUTH0_AUDIENCE || 'https://www.topcoder-dev.com', + AUTH0_AUDIENCE: process.env.AUTH0_AUDIENCE || "https://www.topcoder-dev.com", TOKEN_CACHE_TIME: process.env.TOKEN_CACHE_TIME, AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID, AUTH0_CLIENT_SECRET: process.env.AUTH0_CLIENT_SECRET, // bus API config params - BUSAPI_URL: process.env.BUSAPI_URL || 'https://api.topcoder-dev.com/v5', - KAFKA_ERROR_TOPIC: process.env.KAFKA_ERROR_TOPIC || 'common.error.reporting', - SCHEDULING_TOPIC: process.env.SCHEDULING_TOPIC || 'challenge.notification.schedule.update', + BUSAPI_URL: process.env.BUSAPI_URL || "https://api.topcoder-dev.com/v5", + KAFKA_ERROR_TOPIC: process.env.KAFKA_ERROR_TOPIC || "common.error.reporting", + SCHEDULING_TOPIC: process.env.SCHEDULING_TOPIC || "challenge.notification.schedule.update", AMAZON: { // AWS_ACCESS_KEY_ID: process.env.AWS_FAKE_ID || 'FAKE_ACCESS_KEY', // AWS_SECRET_ACCESS_KEY: process.env.AWS_FAKE_KEY || 'FAKE_SECRET_ACCESS_KEY', - AWS_REGION: process.env.AWS_REGION || 'ap-northeast-1', + AWS_REGION: process.env.AWS_REGION || "ap-northeast-1", IS_LOCAL_DB: process.env.IS_LOCAL_DB || true, - DYNAMODB_URL: process.env.DYNAMODB_URL || 'http://localhost:7777', - S3_API_VERSION: process.env.S3_API_VERSION || '2006-03-01', - BUCKET_WHITELIST: process.env.BUCKET_WHITELIST || 'topcoder_01, topcoder_02' + DYNAMODB_URL: process.env.DYNAMODB_URL || "http://localhost:7777", + S3_API_VERSION: process.env.S3_API_VERSION || "2006-03-01", + BUCKET_WHITELIST: process.env.BUCKET_WHITELIST || "topcoder_01, topcoder_02", }, ES: { // above AWS_REGION is used if we use AWS ES - HOST: process.env.ES_HOST || 'localhost:9200', - API_VERSION: process.env.ES_API_VERSION || '6.8', - ES_INDEX: process.env.ES_INDEX || 'challenge', - ES_TYPE: process.env.ES_TYPE || '_doc', // ES 6.x accepts only 1 Type per index and it's mandatory to define it - ES_REFRESH: process.env.ES_REFRESH || 'true', - TEMP_REINDEXING: process.env.TEMP_REINDEXING || true // if true, it won't delete the existing index when reindexing data + HOST: process.env.ES_HOST || "localhost:9200", + API_VERSION: process.env.ES_API_VERSION || "6.8", + OPENSEARCH: process.env.OPENSEARCH || "false", + ES_INDEX: process.env.ES_INDEX || "challenge", + ES_TYPE: process.env.ES_TYPE || "_doc", + ES_REFRESH: process.env.ES_REFRESH || "true", + TEMP_REINDEXING: process.env.TEMP_REINDEXING || true, // if true, it won't delete the existing index when reindexing data }, // in bytes FILE_UPLOAD_SIZE_LIMIT: process.env.FILE_UPLOAD_SIZE_LIMIT - ? Number(process.env.FILE_UPLOAD_SIZE_LIMIT) : 50 * 1024 * 1024, // 50M + ? Number(process.env.FILE_UPLOAD_SIZE_LIMIT) + : 50 * 1024 * 1024, // 50M // TODO: change this to localhost - SUBMISSIONS_API_URL: process.env.SUBMISSIONS_API_URL || 'https://api.topcoder-dev.com/v5/submissions', - MEMBERS_API_URL: process.env.MEMBERS_API_URL || 'https://api.topcoder-dev.com/v5/members', - RESOURCES_API_URL: process.env.RESOURCES_API_URL || 'http://localhost:4000/v5/resources', + SUBMISSIONS_API_URL: + process.env.SUBMISSIONS_API_URL || "https://api.topcoder-dev.com/v5/submissions", + MEMBERS_API_URL: process.env.MEMBERS_API_URL || "https://api.topcoder-dev.com/v5/members", + RESOURCES_API_URL: process.env.RESOURCES_API_URL || "http://localhost:4000/v5/resources", // TODO: change this to localhost - RESOURCE_ROLES_API_URL: process.env.RESOURCE_ROLES_API_URL || 'http://api.topcoder-dev.com/v5/resource-roles', - GROUPS_API_URL: process.env.GROUPS_API_URL || 'http://localhost:4000/v5/groups', - PROJECTS_API_URL: process.env.PROJECTS_API_URL || 'http://localhost:4000/v5/projects', - TERMS_API_URL: process.env.TERMS_API_URL || 'http://localhost:4000/v5/terms', - CUSTOMER_PAYMENTS_URL: process.env.CUSTOMER_PAYMENTS_URL || 'https://api.topcoder-dev.com/v5/customer-payments', - CHALLENGE_MIGRATION_APP_URL: process.env.CHALLENGE_MIGRATION_APP_URL || 'https://api.topcoder.com/v5/challenge-migration', + RESOURCE_ROLES_API_URL: + process.env.RESOURCE_ROLES_API_URL || "http://api.topcoder-dev.com/v5/resource-roles", + GROUPS_API_URL: process.env.GROUPS_API_URL || "http://localhost:4000/v5/groups", + PROJECTS_API_URL: process.env.PROJECTS_API_URL || "http://localhost:4000/v5/projects", + TERMS_API_URL: process.env.TERMS_API_URL || "http://localhost:4000/v5/terms", + CUSTOMER_PAYMENTS_URL: + process.env.CUSTOMER_PAYMENTS_URL || "https://api.topcoder-dev.com/v5/customer-payments", + CHALLENGE_MIGRATION_APP_URL: + process.env.CHALLENGE_MIGRATION_APP_URL || "https://api.topcoder.com/v5/challenge-migration", // copilot resource role ids allowed to upload attachment COPILOT_RESOURCE_ROLE_IDS: process.env.COPILOT_RESOURCE_ROLE_IDS - ? process.env.COPILOT_RESOURCE_ROLE_IDS.split(',') : ['10ba038e-48da-487b-96e8-8d3b99b6d18b'], - SUBMITTER_ROLE_ID: process.env.SUBMITTER_ROLE_ID || '732339e7-8e30-49d7-9198-cccf9451e221', + ? process.env.COPILOT_RESOURCE_ROLE_IDS.split(",") + : ["10ba038e-48da-487b-96e8-8d3b99b6d18b"], + SUBMITTER_ROLE_ID: process.env.SUBMITTER_ROLE_ID || "732339e7-8e30-49d7-9198-cccf9451e221", - MANAGER_ROLE_ID: process.env.MANAGER_ROLE_ID || '0e9c6879-39e4-4eb6-b8df-92407890faf1', - OBSERVER_ROLE_ID: process.env.OBSERVER_ROLE_ID || '2a4dc376-a31c-4d00-b173-13934d89e286', - CLIENT_MANAGER_ROLE_ID: process.env.OBSERVER_ROLE_ID || '9b2f1905-8128-42da-85df-ed64410f4781', + MANAGER_ROLE_ID: process.env.MANAGER_ROLE_ID || "0e9c6879-39e4-4eb6-b8df-92407890faf1", + OBSERVER_ROLE_ID: process.env.OBSERVER_ROLE_ID || "2a4dc376-a31c-4d00-b173-13934d89e286", + CLIENT_MANAGER_ROLE_ID: process.env.OBSERVER_ROLE_ID || "9b2f1905-8128-42da-85df-ed64410f4781", // topgear billing accounts - TOPGEAR_BILLING_ACCOUNTS_ID: process.env.TOPGEAR_BILLING_ACCOUNTS_ID ? process.env.TOPGEAR_BILLING_ACCOUNTS_ID.split(',') : [], + TOPGEAR_BILLING_ACCOUNTS_ID: process.env.TOPGEAR_BILLING_ACCOUNTS_ID + ? process.env.TOPGEAR_BILLING_ACCOUNTS_ID.split(",") + : [], // health check timeout in milliseconds HEALTH_CHECK_TIMEOUT: process.env.HEALTH_CHECK_TIMEOUT || 3000, SCOPES: { - READ: process.env.SCOPE_CHALLENGES_READ || 'read:challenges', - CREATE: process.env.SCOPE_CHALLENGES_CREATE || 'create:challenges', - UPDATE: process.env.SCOPE_CHALLENGES_UPDATE || 'update:challenges', - DELETE: process.env.SCOPE_CHALLENGES_DELETE || 'delete:challenges', - ALL: process.env.SCOPE_CHALLENGES_ALL || 'all:challenges' + READ: process.env.SCOPE_CHALLENGES_READ || "read:challenges", + CREATE: process.env.SCOPE_CHALLENGES_CREATE || "create:challenges", + UPDATE: process.env.SCOPE_CHALLENGES_UPDATE || "update:challenges", + DELETE: process.env.SCOPE_CHALLENGES_DELETE || "delete:challenges", + ALL: process.env.SCOPE_CHALLENGES_ALL || "all:challenges", }, - DEFAULT_CONFIDENTIALITY_TYPE: process.env.DEFAULT_CONFIDENTIALITY_TYPE || 'public', + DEFAULT_CONFIDENTIALITY_TYPE: process.env.DEFAULT_CONFIDENTIALITY_TYPE || "public", - M2M_AUDIT_HANDLE: process.env.M2M_AUDIT_HANDLE || 'tcwebservice', + M2M_AUDIT_HANDLE: process.env.M2M_AUDIT_HANDLE || "tcwebservice", + M2M_AUDIT_USERID: process.env.M2M_AUDIT_USERID || 22838965, FORUM_TITLE_LENGTH_LIMIT: process.env.FORUM_TITLE_LENGTH_LIMIT || 90, - NEW_SELF_SERVICE_PROJECT_TYPE: process.env.NEW_SELF_SERVICE_PROJECT_TYPE || 'self-service', + NEW_SELF_SERVICE_PROJECT_TYPE: process.env.NEW_SELF_SERVICE_PROJECT_TYPE || "self-service", AXIOS_RETRIES: process.env.AXIOS_RETRIES || 3, SENDGRID_TEMPLATES: { - WORK_REQUEST_SUBMITTED: process.env.WORK_REQUEST_SUBMITTED || '', - WORK_REQUEST_STARTED: process.env.WORK_REQUEST_STARTED || '', - WORK_REQUEST_REDIRECTED: process.env.WORK_REQUEST_REDIRECTED || '', - WORK_COMPLETED: process.env.WORK_COMPLETED || '' + WORK_REQUEST_SUBMITTED: process.env.WORK_REQUEST_SUBMITTED || "", + WORK_REQUEST_STARTED: process.env.WORK_REQUEST_STARTED || "", + WORK_REQUEST_REDIRECTED: process.env.WORK_REQUEST_REDIRECTED || "", + WORK_COMPLETED: process.env.WORK_COMPLETED || "", }, - EMAIL_FROM: process.env.EMAIL_FROM || 'no-reply@topcoder.com', - SELF_SERVICE_EMAIL_CC_ACCOUNTS: process.env.SELF_SERVICE_EMAIL_CC_ACCOUNTS ? _.map(process.env.SELF_SERVICE_EMAIL_CC_ACCOUNTS.split(','), email => ({ email })) : [{ email: 'sathya.jayabal@gmail.com' }], - SELF_SERVICE_WHITELIST_HANDLES: process.env.SELF_SERVICE_WHITELIST_HANDLES ? process.env.SELF_SERVICE_WHITELIST_HANDLES.split(',') : ['TCConnCopilot', 'sstestcopilot'], - SELF_SERVICE_APP_URL: process.env.SELF_SERVICE_APP_URL || 'https://platform.topcoder-dev.com/self-service', - ZENDESK_API_TOKEN: process.env.ZENDESK_API_TOKEN || '', - ZENDESK_API_URL: process.env.ZENDESK_API_URL || '', + EMAIL_FROM: process.env.EMAIL_FROM || "no-reply@topcoder.com", + SELF_SERVICE_EMAIL_CC_ACCOUNTS: process.env.SELF_SERVICE_EMAIL_CC_ACCOUNTS + ? _.map(process.env.SELF_SERVICE_EMAIL_CC_ACCOUNTS.split(","), (email) => ({ email })) + : [{ email: "sathya.jayabal@gmail.com" }], + SELF_SERVICE_WHITELIST_HANDLES: process.env.SELF_SERVICE_WHITELIST_HANDLES + ? process.env.SELF_SERVICE_WHITELIST_HANDLES.split(",") + : ["TCConnCopilot", "sstestcopilot"], + SELF_SERVICE_APP_URL: + process.env.SELF_SERVICE_APP_URL || "https://platform.topcoder-dev.com/self-service", + ZENDESK_API_TOKEN: process.env.ZENDESK_API_TOKEN || "", + ZENDESK_API_URL: process.env.ZENDESK_API_URL || "", ZENDESK_CUSTOM_FIELD_TAG_ID: process.env.ZENDESK_CUSTOM_FIELD_TAG_ID, - ZENDESK_DEFAULT_PRIORITY: process.env.ZENDESK_DEFAULT_PRIORITY || 'high', - INTERNAL_CACHE_TTL: process.env.INTERNAL_CACHE_TTL || 1800 -} + ZENDESK_DEFAULT_PRIORITY: process.env.ZENDESK_DEFAULT_PRIORITY || "high", + INTERNAL_CACHE_TTL: process.env.INTERNAL_CACHE_TTL || 1800, + GRPC_CHALLENGE_SERVER_HOST: process.env.GRPC_DOMAIN_CHALLENGE_SERVER_HOST || "localhost", + GRPC_CHALLENGE_SERVER_PORT: process.env.GRPC_DOMAIN_CHALLENGE_SERVER_PORT || 8888, +}; diff --git a/docker/Dockerfile b/docker/Dockerfile index 2a9b952c..89879a2c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,5 @@ # Use the base image with Node.js -FROM node:14.21.2-bullseye +FROM node:18.14.1-alpine3.17 # Copy the current directory into the Docker image COPY . /challenge-api diff --git a/docs/prod.env b/docs/prod.env index 3393a3c8..7c022cd8 100644 --- a/docs/prod.env +++ b/docs/prod.env @@ -14,7 +14,6 @@ S3_API_VERSION= ES_HOST= ES_API_VERSION= ES_INDEX= -ES_TYPE= ES_REFRESH=true RESOURCES_API_URL= GROUPS_API_URL= diff --git a/local/docker-compose.yml b/local/docker-compose.yml index 88b4db1c..b5e97b5f 100644 --- a/local/docker-compose.yml +++ b/local/docker-compose.yml @@ -1,33 +1,33 @@ version: '3' services: - dynamodb: - image: tray/dynamodb-local - ports: - - "8000:8000" - command: "-inMemory -port 8000" + # dynamodb: + # image: amazon/dynamodb-local + # ports: + # - "8000:8000" + # command: "-inMemory -port 8000" esearch: image: "docker.elastic.co/elasticsearch/elasticsearch:6.8.0" ports: - "9200:9200" environment: - "discovery.type=single-node" - minio1: - image: minio/minio - ports: - - "9000:9000" - environment: - MINIO_ACCESS_KEY: "FAKE_ACCESS_KEY" - MINIO_SECRET_KEY: "FAKE_SECRET_ACCESS_KEY" - command: "server /data" - mock-api: - image: mock-api:latest - build: - context: ../ - dockerfile: mock-api/Dockerfile - volumes: - - ../mock-api:/challenge-api/mock-api - environment: - DYNAMODB_URL: http://dynamodb:7777 - IS_LOCAL_DB: "true" - ports: - - "4000:4000" + # minio1: + # image: minio/minio + # ports: + # - "9000:9000" + # environment: + # MINIO_ACCESS_KEY: "FAKE_ACCESS_KEY" + # MINIO_SECRET_KEY: "FAKE_SECRET_ACCESS_KEY" + # command: "server /data" + # mock-api: + # image: mock-api:latest + # build: + # context: ../ + # dockerfile: mock-api/Dockerfile + # volumes: + # - ../mock-api:/challenge-api/mock-api + # environment: + # DYNAMODB_URL: http://dynamodb:7777 + # IS_LOCAL_DB: "true" + # ports: + # - "4000:4000" diff --git a/local/start-xray-daemon.sh b/local/start-xray-daemon.sh new file mode 100755 index 00000000..a54dbc9b --- /dev/null +++ b/local/start-xray-daemon.sh @@ -0,0 +1,7 @@ +docker run --attach STDOUT \ + -e AWS_REGION=${AWS_REGION} \ + -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \ + -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \ + -e AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} \ + --publish 2000:2000/udp \ + public.ecr.aws/xray/aws-xray-daemon -o \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 8c0bc8cd..00000000 --- a/package-lock.json +++ /dev/null @@ -1,5351 +0,0 @@ -{ - "name": "topcoder-challenges-api", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.16.7" - } - }, - "@babel/generator": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", - "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", - "dev": true, - "requires": { - "@babel/types": "^7.18.2", - "@jridgewell/gen-mapping": "^0.3.0", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", - "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", - "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", - "dev": true, - "requires": { - "@babel/template": "^7.16.7", - "@babel/types": "^7.17.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", - "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "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, - "requires": { - "color-convert": "^1.9.0" - } - }, - "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, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "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, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.18.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", - "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", - "dev": true - }, - "@babel/runtime": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", - "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", - "requires": { - "regenerator-runtime": "^0.13.11" - } - }, - "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/traverse": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.2.tgz", - "integrity": "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-environment-visitor": "^7.18.2", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.18.0", - "@babel/types": "^7.18.2", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "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 - } - } - }, - "@babel/types": { - "version": "7.18.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", - "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - } - }, - "@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" - }, - "@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "requires": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", - "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/chai": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz", - "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==", - "dev": true - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", - "dev": true - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-jwt": { - "version": "0.0.42", - "resolved": "https://registry.npmjs.org/@types/express-jwt/-/express-jwt-0.0.42.tgz", - "integrity": "sha512-WszgUddvM1t5dPpJ3LhWNH8kfNN8GPIBrAGxgIYXVCEGx6Bx4A036aAuf/r5WH9DIEdlmp7gHOYvSM6U87B0ag==", - "requires": { - "@types/express": "*", - "@types/express-unless": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/express-unless": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@types/express-unless/-/express-unless-0.5.3.tgz", - "integrity": "sha512-TyPLQaF6w8UlWdv4gj8i46B+INBVzURBNRahCozCSXfsK2VTlL1wNyTlMKw817VHygBtlcl5jfnPadlydr06Yw==", - "requires": { - "@types/express": "*" - } - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" - }, - "@types/node": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.0.tgz", - "integrity": "sha512-D5Rt+HXgEywr3RQJcGlZUCTCx1qVbCZpVk3/tOOA6spLNZdGm8BU+zRgdRYDoF1pO3RuXLxADzMrF903JlQXqg==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/superagent": { - "version": "3.8.7", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.8.7.tgz", - "integrity": "sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA==", - "dev": true, - "requires": { - "@types/cookiejar": "*", - "@types/node": "*" - } - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "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==" - } - } - }, - "agentkeepalive": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", - "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", - "requires": { - "humanize-ms": "^1.2.1" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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" - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true - }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==" - }, - "append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", - "dev": true, - "requires": { - "default-require-extensions": "^2.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - } - }, - "array.prototype.reduce": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.4.tgz", - "integrity": "sha512-WnM+AjG/DvLRLo4DDl+r+SvCzYtD2Jd9oeBYMcEaI7t3fFrHY9M53/wdLcTvmZNQ70IU6Htj0emFkZ5TS+lrdw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - } - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "aws-sdk": { - "version": "2.1146.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1146.0.tgz", - "integrity": "sha512-lg83hvrK2oiJVnklUVMXIJkeYX2nlqhvxIFlZ2wfoaJyvdGsEcOUdZ/EMDgiS0V2jwGS8CtTUypcW/t2S6gdcQ==", - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.16.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "8.0.0", - "xml2js": "0.4.19" - }, - "dependencies": { - "uuid": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", - "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==" - } - } - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", - "requires": { - "follow-redirects": "1.5.10" - } - }, - "axios-retry": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.3.1.tgz", - "integrity": "sha512-RohAUQTDxBSWLFEnoIG/6bvmy8l3TfpkclgStjl5MDCMBDgapAWCmr1r/9harQfWC8bzLC8job6UcL1A1Yc+/Q==", - "requires": { - "@babel/runtime": "^7.15.4", - "is-retry-allowed": "^2.2.0" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", - "dev": true - } - } - }, - "babel-runtime": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.6.1.tgz", - "integrity": "sha512-5pdhO3jaxqh9L42oBfbrqy58swDhciM47sRGoODURdRxwfiqttEvK87LX27W/PYY6f4cJt2mEdyoLcr/+cM/iw==", - "requires": { - "core-js": "^2.1.0" - } - }, - "backoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", - "integrity": "sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==", - "requires": { - "precond": "0.2" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, - "bunyan": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", - "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==", - "requires": { - "dtrace-provider": "~0.8", - "moment": "^2.19.3", - "mv": "~2", - "safe-json-stringify": "~1" - } - }, - "busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "requires": { - "streamsearch": "^1.1.0" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "caching-transform": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", - "dev": true, - "requires": { - "hasha": "^3.0.0", - "make-dir": "^2.0.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.4.2" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha512-UJiE1otjXPF5/x+T3zTnSFiTOEmJoGTD9HmBoxnCUwho61a2eSNn/VwtwuIBDAo2SEOv1AJ7ARI5gCmohFLu/g==", - "dev": true, - "requires": { - "callsites": "^0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha512-Zv4Dns9IbXXmPkgRRUjAaJQgfN4xX5p6+RQFhWUqscdvvK2xK/ZL8b3IXIJsj+4sD+f24NwnWy2BY8AJ82JB0A==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" - }, - "chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - } - }, - "chai-http": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.3.0.tgz", - "integrity": "sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg==", - "dev": true, - "requires": { - "@types/chai": "4", - "@types/superagent": "^3.8.3", - "cookiejar": "^2.1.1", - "is-ip": "^2.0.0", - "methods": "^1.1.2", - "qs": "^6.5.1", - "superagent": "^3.7.0" - } - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==", - "dev": true - }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", - "dev": true - }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "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" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" - }, - "codependency": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/codependency/-/codependency-0.1.4.tgz", - "integrity": "sha512-26yAvd3+17xSfDADtnzpnL5GK+8+x4QeZ3DegekkHyno6LWeHqXuSU7q8w/IrAur7SY6ISPApOWtWTfuIF0Xpg==", - "requires": { - "semver": "5.0.1" - }, - "dependencies": { - "semver": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.1.tgz", - "integrity": "sha512-Ne6/HdGZvvpXBdjW3o8J0pvxC2jnmVNBK7MKkMgsOBfrsIdTXfA5x+H9DUbQ2xzyvnLv0A0v9x8R4B40xNZIRQ==" - } - } - }, - "color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "requires": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "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==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "requires": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "config": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/config/-/config-3.3.7.tgz", - "integrity": "sha512-mX/n7GKDYZMqvvkY6e6oBY49W8wxdmQt+ho/5lhwFDXqQW9gI+Ahp8EKp8VAbISPnmf2+Bv5uZK7lKXZ6pf1aA==", - "requires": { - "json5": "^2.1.1" - } - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha512-OKZnPGeMQy2RPaUIBPFFd71iNf4791H12MCRuVQDnzGRwCYNYmTDy5pdafo2SLAcEMKzTOQnLWG4QdcjeJUMEg==", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "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==", - "dev": true - } - } - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "cookiejar": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==" - }, - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "cp-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", - "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "make-dir": "^2.0.0", - "nested-error-stacks": "^2.0.0", - "pify": "^4.0.1", - "safe-buffer": "^5.0.1" - } - }, - "cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "cssfilter": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz", - "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "debug-log": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", - "integrity": "sha512-gV/pe1YIaKNgLYnd1g9VNW80tcb7oV5qvNUxG7NM8rbDpnl6RGunzlAtlGSb0wEs3nesu2vHNiX9TSsZ+Y+RjA==", - "dev": true - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==" - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha512-B0n2zDIXpzLzKeoEozorDSa1cHc1t0NjmxP0zuAxbizNU2MBqYJJKYXrrFdKuQliojXynrxgd7l4ahfg/+aA5g==", - "dev": true, - "requires": { - "strip-bom": "^3.0.0" - } - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "deglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", - "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", - "dev": true, - "requires": { - "find-root": "^1.0.0", - "glob": "^7.0.5", - "ignore": "^3.0.9", - "pkg-config": "^1.1.0", - "run-parallel": "^1.1.2", - "uniq": "^1.0.1" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "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" - } - }, - "dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==" - }, - "dtrace-provider": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", - "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", - "optional": true, - "requires": { - "nan": "^2.14.0" - } - }, - "dynamoose": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/dynamoose/-/dynamoose-1.11.1.tgz", - "integrity": "sha512-73T0GOeSh2FQDdK5V+cN9yowFU4uVt2OsOvknCB4Xdb+nSL/hBaecPY/meJaWZApVx73Hl1DcBSCGp/VWMvfRA==", - "requires": { - "@types/node": "11.11.0", - "aws-sdk": "2.395.0", - "debug": "4.1.1", - "deep-equal": "1.0.1", - "hooks": "0.3.2", - "object-path": "0.11.4", - "q": "1.5.1" - }, - "dependencies": { - "aws-sdk": { - "version": "2.395.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.395.0.tgz", - "integrity": "sha512-ldTTjctniZT4E2lq2z3D8Y2u+vpkp+laoEnDkXgjKXTKbiJ0QEtfWsUdx/IQ7awCt8stoxyqZK47DJOxIbRNoA==", - "requires": { - "buffer": "4.9.1", - "events": "1.1.1", - "ieee754": "1.1.8", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - } - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha512-DNK4ruAqtyHaN8Zne7PkBTO+dD1Lr0YfTduMqlIyjvQIoztBkUxrvL+hKeLW8NXFKHOq/2upkxuoS9znQ9bW9A==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha512-/aoyv2Nt7mGLnCAWzE0C1WH9Xd8ZsqR0f4Pjwxputi1JNm01+InyAYQotF4N+ulEIjbEsJo22NOHr+U/XEZ1Pw==" - }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha512-+kHj8HXArPfpPEKGLZ+kB5ONRTCiGQXo8RQYL0hH8t6pWXUBBK5KkkQmTNOwKK4LEsd0yTsgtjJVm4UBSZea4w==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "elasticsearch": { - "version": "16.7.3", - "resolved": "https://registry.npmjs.org/elasticsearch/-/elasticsearch-16.7.3.tgz", - "integrity": "sha512-e9kUNhwnIlu47fGAr4W6yZJbkpsgQJB0TqNK8rCANe1J4P65B1sGnbCFTgcKY3/dRgCWnuP1AJ4obvzW604xEQ==", - "requires": { - "agentkeepalive": "^3.4.1", - "chalk": "^1.0.0", - "lodash": "^4.17.10" - } - }, - "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 - }, - "enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "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" - }, - "dependencies": { - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - } - } - }, - "es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "dependencies": { - "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" - } - } - } - }, - "es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true - }, - "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-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "eslint": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.4.0.tgz", - "integrity": "sha512-UIpL91XGex3qtL6qwyCQJar2j3osKxK9e3ano3OcGEIRM4oWIpCkDg9x95AXEC2wMs7PnxzOkPZ2gq+tsMS9yg==", - "dev": true, - "requires": { - "ajv": "^6.5.0", - "babel-code-frame": "^6.26.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.2", - "imurmurhash": "^0.1.4", - "inquirer": "^5.2.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.11.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.5", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^2.0.0", - "require-uncached": "^1.0.3", - "semver": "^5.5.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^4.0.3", - "text-table": "^0.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true - }, - "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, - "requires": { - "color-convert": "^1.9.0" - } - }, - "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, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "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" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "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, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "eslint-config-standard": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz", - "integrity": "sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ==", - "dev": true - }, - "eslint-config-standard-jsx": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-6.0.2.tgz", - "integrity": "sha512-D+YWAoXw+2GIdbMBRAzWwr1ZtvnSf4n4yL0gKGg7ShUOGXkSOLerI17K4F6LdQMJPNMoWYqepzQD/fKY+tXNSg==", - "dev": true - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.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-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.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" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "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": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "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 - }, - "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": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true - } - } - }, - "eslint-plugin-es": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.1.tgz", - "integrity": "sha512-5fa/gR2yR3NxQf+UXkeLeP8FBBl6tSgdrAz1+cF84v1FMM4twGwQoqTnn+QxFLcPOrF4pdKEJKDB/q9GoyJrCA==", - "dev": true, - "requires": { - "eslint-utils": "^1.4.2", - "regexpp": "^2.0.1" - } - }, - "eslint-plugin-import": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", - "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", - "dev": true, - "requires": { - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "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": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - } - } - }, - "eslint-plugin-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz", - "integrity": "sha512-lfVw3TEqThwq0j2Ba/Ckn2ABdwmL5dkOgAux1rvOk6CO7A6yGyPI2+zIxN6FyNkp1X1X/BSvKOceD6mBWSj4Yw==", - "dev": true, - "requires": { - "eslint-plugin-es": "^1.3.1", - "eslint-utils": "^1.3.1", - "ignore": "^4.0.2", - "minimatch": "^3.0.4", - "resolve": "^1.8.1", - "semver": "^5.5.0" - } - }, - "eslint-plugin-promise": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz", - "integrity": "sha512-Si16O0+Hqz1gDHsys6RtFRrW7cCTB6P7p3OJmKp3Y3dxpQE2qwOA7d3xnV+0mBmrPoi0RBnxlCKvqu70te6wjg==", - "dev": true - }, - "eslint-plugin-react": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz", - "integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==", - "dev": true, - "requires": { - "array-includes": "^3.0.3", - "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1", - "prop-types": "^15.6.2" - } - }, - "eslint-plugin-standard": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.2.tgz", - "integrity": "sha512-nKptN8l7jksXkwFk++PhJB3cCDTcXOEyhISIN86Ue2feJ1LFyY3PrY3/xT2keXlJSY5bpmbiTG0f885/YKAvTA==", - "dev": true - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.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==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "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 - }, - "espree": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", - "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", - "dev": true, - "requires": { - "acorn": "^6.0.2", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "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": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==" - }, - "express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "express-fileupload": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.4.0.tgz", - "integrity": "sha512-RjzLCHxkv3umDeZKeFeMg8w7qe0V09w3B7oGZprr/oO2H/ISCgNzuqzn7gV3HRWb37GjRk429CCpSLS2KNTqMQ==", - "requires": { - "busboy": "^1.6.0" - } - }, - "express-interceptor": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/express-interceptor/-/express-interceptor-1.2.0.tgz", - "integrity": "sha512-fCbcJv8ZwabDg0M/3PmHUxfr/WKHGMpAicR9TfGdhANV4M1GBDSrBTenHIK3aegyRN5S6eDwlvyNFiLynnc19w==", - "requires": { - "debug": "^2.2.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha512-uXP/zGzxxFvFfcZGgBIwotm+Tdc55ddPAzF7iHshP4YGaXMww7rSF9peD9D1sui5ebONg5UobsZv+FfgEpGv/w==", - "dev": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", - "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", - "dev": true, - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - } - }, - "foreground-child": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha512-3TOY+4TKV0Ml83PXJQY+JFQaHNV38lzQDIzzXYg1kWdBLenGgoZhAs0CKgzI31vi2pWEpQMq/Yi4bpKwCPkw7g==", - "dev": true, - "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", - "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==" - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "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", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", - "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==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-parameter-names": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/get-parameter-names/-/get-parameter-names-0.3.0.tgz", - "integrity": "sha512-KkR1dX7U1TynXFkqveVE/XoRn9qRAsM2q4Eu2WsGTFzoaSdnNQEfxbcK+LMv8DcFoQQT9BFjNL+bf9ZyTLkWpg==" - }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==", - "optional": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "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 - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "hasha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha512-w0Kz8lJFBoyaurBiNrIvxPqr/gJ6fOfSkpAPOepN3oECqGJag37xPbOv57izi/KP8auHgNYxn5fXtAb+1LsJ6w==", - "dev": true, - "requires": { - "is-stream": "^1.0.1" - }, - "dependencies": { - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true - } - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==" - }, - "hooks": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/hooks/-/hooks-0.3.2.tgz", - "integrity": "sha512-TqeFzUf12rSzcbm5lUls81jimUC8TmXZ4ANPxxeeMou09hrjBcHYhAQ0WgyN5YqNCXOzz7L6xVNl/+ctFuSeOw==" - }, - "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 - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-aws-es": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/http-aws-es/-/http-aws-es-6.0.0.tgz", - "integrity": "sha512-g+qp7J110/m4aHrR3iit4akAlnW0UljZ6oTq/rCcbsI8KP9x+95vqUtx49M2XQ2JMpwJio3B6gDYx+E8WDxqiA==" - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "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==" - } - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "http-status-codes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-1.4.0.tgz", - "integrity": "sha512-JrT3ua+WgH8zBD3HEJYbeEgnuQaAnUeRRko/YojPAJjGmIfGD3KPU/asLdsLwKjfxOmQe5nXMQ0pt/7MyapVbQ==" - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "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==" - } - } - }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "requires": { - "ms": "^2.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "inquirer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", - "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.1.0", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^5.5.2", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true - }, - "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, - "requires": { - "color-convert": "^1.9.0" - } - }, - "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, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "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, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", - "dev": true - }, - "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==" - }, - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true - }, - "is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "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": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true - }, - "is-ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", - "integrity": "sha512-9MTn0dteHETtyUx8pxqMwg5hMBi3pvlyglJ+b79KOCca0po23337LbVV2Hl4xmMvfw++ljnO0/+5G6G+0Szh6g==", - "dev": true, - "requires": { - "ip-regex": "^2.0.0" - } - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "is-retry-allowed": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", - "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==" - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "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" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "requires": { - "punycode": "2.x.x" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" - }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", - "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", - "dev": true, - "requires": { - "append-transform": "^1.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "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 - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "istanbul-reports": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", - "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0" - } - }, - "jmespath": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", - "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" - }, - "joi": { - "version": "14.3.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz", - "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==", - "requires": { - "hoek": "6.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "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": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "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==" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" - }, - "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "jsx-ast-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", - "integrity": "sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==", - "dev": true, - "requires": { - "array-includes": "^3.1.1", - "object.assign": "^4.1.0" - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jwks-rsa": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-1.12.3.tgz", - "integrity": "sha512-cFipFDeYYaO9FhhYJcZWX/IyZgc0+g316rcHnDpT2dNRNIE/lMOmWKKqp09TkJoYlNFzrEVODsR4GgXJMgWhnA==", - "requires": { - "@types/express-jwt": "0.0.42", - "axios": "^0.21.1", - "debug": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "jsonwebtoken": "^8.5.1", - "limiter": "^1.1.5", - "lru-memoizer": "^2.1.2", - "ms": "^2.1.2", - "proxy-from-env": "^1.1.0" - }, - "dependencies": { - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "requires": { - "follow-redirects": "^1.14.0" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "follow-redirects": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", - "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "limiter": { - "version": "1.1.5", - "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": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true - } - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - }, - "dependencies": { - "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, - "requires": { - "color-convert": "^1.9.0" - } - }, - "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, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "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, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "logform": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.0.tgz", - "integrity": "sha512-CPSJw4ftjf517EhXZGGvTHHkYobo7ZCc0kvwUoOYcjfR2UVrI66RHj8MCrfAdEitdmFqbu2BYdYs8FHHZSb6iw==", - "requires": { - "@colors/colors": "1.5.0", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", - "dev": true, - "requires": { - "get-func-name": "^2.0.0" - } - }, - "lru-cache": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", - "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", - "requires": { - "pseudomap": "^1.0.1", - "yallist": "^2.0.0" - } - }, - "lru-memoizer": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.4.tgz", - "integrity": "sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==", - "requires": { - "lodash.clonedeep": "^4.5.0", - "lru-cache": "~4.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "requires": { - "source-map": "^0.6.1" - } - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - }, - "millisecond": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/millisecond/-/millisecond-0.1.2.tgz", - "integrity": "sha512-BJ8XtxY+woL+5TkP6uS6XvOArm0JVrX2otkgtWZseHpIax0oOOPW3cnwhOjRqbEJg7YRO/BDF7fO/PTWNT3T9Q==" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "requires": { - "minimist": "^1.2.6" - } - }, - "mocha": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", - "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.4", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "mkdirp": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", - "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "mocha-prepare": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/mocha-prepare/-/mocha-prepare-0.1.0.tgz", - "integrity": "sha512-ZSa/Zq+CQv9ZS7kfgsB3iRbfM4WBLn+Oy3EHDp3IXxbUVmVrcu+cs2YOELH77Gj3amkHjhCpM5CAZHV6jz6scg==", - "dev": true - }, - "moment": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz", - "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true - }, - "mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==", - "optional": true, - "requires": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - } - }, - "nan": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", - "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", - "optional": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", - "optional": true - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "nested-error-stacks": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", - "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", - "dev": true - }, - "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-cache": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", - "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", - "requires": { - "clone": "2.x" - } - }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "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" - } - }, - "nyc": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", - "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "caching-transform": "^3.0.2", - "convert-source-map": "^1.6.0", - "cp-file": "^6.2.0", - "find-cache-dir": "^2.1.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.5", - "istanbul-lib-hook": "^2.0.7", - "istanbul-lib-instrument": "^3.3.0", - "istanbul-lib-report": "^2.0.8", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^2.2.4", - "js-yaml": "^3.13.1", - "make-dir": "^2.1.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.2.3", - "uuid": "^3.3.2", - "yargs": "^13.2.2", - "yargs-parser": "^13.0.0" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "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-path": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz", - "integrity": "sha512-ICbQN+aw/eAASDtaC7+SJXSAruz7fvvNjxMFfS3mTdvZaaiuuw81XXYu+9CSJeUVrS3YpRhTr862YGywMQUOWg==" - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.4.tgz", - "integrity": "sha512-sccv3L/pMModT6dJAYF3fzGMVcb38ysQ0tEE6ixv2yXJDtEIPph268OlAdJj5/qZMZDq2g/jqvwppt36uS/uQQ==", - "dev": true, - "requires": { - "array.prototype.reduce": "^1.0.4", - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.1" - } - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "requires": { - "fn.name": "1.x.x" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "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" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "package-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", - "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "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": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "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": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "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": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "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" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true - } - } - }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "pkg-conf": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", - "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "load-json-file": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "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": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "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": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true - } - } - }, - "pkg-config": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", - "integrity": "sha512-ft/WI9YK6FuTuw4Ql+QUaNXtm/ASQNqDUUsZEgFZKyFpW6amyP8Gx01xrRs8KdiNbbqXfYxkOXplpq1euWbOjw==", - "dev": true, - "requires": { - "debug-log": "^1.0.0", - "find-root": "^1.0.0", - "xtend": "^4.0.1" - } - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, - "precond": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", - "integrity": "sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ==" - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==" - }, - "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "r7insight_node": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/r7insight_node/-/r7insight_node-1.8.4.tgz", - "integrity": "sha512-6cQrzLkaOxdv/SRFXWRJjgFr8a3nXUOT/4IMFuBv+mWzBnu5DJl+HzONAsWYvclrlZnvfa54PaIPqPuPRSlbrQ==", - "requires": { - "babel-runtime": "6.6.1", - "codependency": "0.1.4", - "json-stringify-safe": "5.0.1", - "lodash": "4.17.15", - "reconnect-core": "1.3.0", - "semver": "5.1.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "semver": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.1.0.tgz", - "integrity": "sha512-sfKXKhcz5XVyfUZa2V4RbjK0xjOJCMLNF9H4p4v0UCo9wNHM/lH9RDuyDbGEtxWLMDlPBc8xI7AbbVLKXty+rQ==" - } - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "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==" - } - } - }, - "reconnect-core": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/reconnect-core/-/reconnect-core-1.3.0.tgz", - "integrity": "sha512-+gLKwmyRf2tjl6bLR03DoeWELzyN6LW9Xgr3vh7NXHHwPi0JC0N2TwPyf90oUEBkCRcD+bgQ+s3HORoG3nwHDg==", - "requires": { - "backoff": "~2.5.0" - } - }, - "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" - } - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha512-Xct+41K3twrbBHdxAgMoOS+cNcoqIjfM2/VxBF4LL2hVph7YsF8VSKyQ3BDFZwEVbok9yeDl2le/qo0S77WG2w==", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha512-kT10v4dhrlLNcnO084hEjvXCI1wUG9qZLoz2RogxqDQQYy7IxjI/iMUkOtQTNEh6rzHxvdQWHsJyel1pKOVCxg==", - "dev": true - } - } - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==", - "optional": true, - "requires": { - "glob": "^6.0.1" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "5.5.12", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", - "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", - "dev": true, - "requires": { - "symbol-observable": "1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safe-json-stringify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", - "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", - "optional": true - }, - "safe-stable-stringify": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz", - "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "requires": { - "is-arrayish": "^0.3.1" - } - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "spawn-wrap": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", - "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", - "dev": true, - "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "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.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" - }, - "standard": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/standard/-/standard-12.0.1.tgz", - "integrity": "sha512-UqdHjh87OG2gUrNCSM4QRLF5n9h3TFPwrCNyVlkqu31Hej0L/rc8hzKqVvkb2W3x0WMq7PzZdkLfEcBhVOR6lg==", - "dev": true, - "requires": { - "eslint": "~5.4.0", - "eslint-config-standard": "12.0.0", - "eslint-config-standard-jsx": "6.0.2", - "eslint-plugin-import": "~2.14.0", - "eslint-plugin-node": "~7.0.1", - "eslint-plugin-promise": "~4.0.0", - "eslint-plugin-react": "~7.11.1", - "eslint-plugin-standard": "~4.0.0", - "standard-engine": "~9.0.0" - } - }, - "standard-engine": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-9.0.0.tgz", - "integrity": "sha512-ZfNfCWZ2Xq67VNvKMPiVMKHnMdvxYzvZkf1AH8/cw2NLDBm5LRsxMqvEJpsjLI/dUosZ3Z1d6JlHDp5rAvvk2w==", - "dev": true, - "requires": { - "deglob": "^2.1.0", - "get-stdin": "^6.0.0", - "minimist": "^1.1.0", - "pkg-conf": "^2.0.0" - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "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==" - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true - }, - "superagent": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", - "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", - "requires": { - "component-emitter": "^1.2.0", - "cookiejar": "^2.1.0", - "debug": "^3.1.0", - "extend": "^3.0.0", - "form-data": "^2.3.1", - "formidable": "^1.2.0", - "methods": "^1.1.1", - "mime": "^1.4.1", - "qs": "^6.5.1", - "readable-stream": "^2.3.5" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==" - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "swagger-ui-dist": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.11.1.tgz", - "integrity": "sha512-pf3kfSTYdF9mYFY2VnfJ51wnXlSVhEGdtymhpHzfbFw2jTbiEWgBoVz5EB9aW2EaJvUGTM1YHAXYZX7Jk4RdAQ==" - }, - "swagger-ui-express": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.4.0.tgz", - "integrity": "sha512-1CzRkHG386VQMVZK406jcpgnW2a9A5A/NiAjKhsFTQqUBWRF+uGbXTU/mA7WSV3mTzyOQDvjBdWP/c2qd5lqKw==", - "requires": { - "swagger-ui-dist": ">=4.11.0" - } - }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha512-Kb3PrPYz4HanVF1LVGuAdW6LoVgIwjUYJGzFe7NDrBLCN4lsV/5J0MFurV+ygS4bRVwrCEt2c7MQ1R2a72oJDw==", - "dev": true - }, - "table": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", - "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", - "dev": true, - "requires": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - }, - "dependencies": { - "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, - "requires": { - "color-convert": "^1.9.0" - } - }, - "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, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "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, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "tc-core-library-js": { - "version": "github:appirio-tech/tc-core-library-js#df0b36c51cf80918194cbff777214b3c0cf5a151", - "from": "github:appirio-tech/tc-core-library-js#v2.6.4", - "requires": { - "axios": "^0.19.0", - "bunyan": "^1.8.12", - "jsonwebtoken": "^8.5.1", - "jwks-rsa": "^1.6.0", - "lodash": "^4.17.15", - "millisecond": "^0.1.2", - "r7insight_node": "^1.8.4", - "request": "^2.88.0" - } - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "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-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "topcoder-bus-api-wrapper": { - "version": "github:topcoder-platform/tc-bus-api-wrapper#f8cbd335a0e0b4d6edd7cae859473593271fd97f", - "from": "github:topcoder-platform/tc-bus-api-wrapper", - "requires": { - "joi": "^13.4.0", - "lodash": "^4.17.15", - "superagent": "^3.8.3", - "tc-core-library-js": "github:appirio-tech/tc-core-library-js#v2.6.4" - }, - "dependencies": { - "hoek": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", - "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==" - }, - "joi": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz", - "integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==", - "requires": { - "hoek": "5.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" - } - } - } - }, - "topo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", - "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", - "requires": { - "hoek": "6.x.x" - } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } - } - }, - "triple-beam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } - } - }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "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", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "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" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "winston": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.7.2.tgz", - "integrity": "sha512-QziIqtojHBoyzUOdQvQiar1DH0Xp9nF1A1y7NVy2DGEsz82SBDtOalS0ulTRGVT14xPX3WRWkCsdcJKqNflKng==", - "requires": { - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.5.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "winston-transport": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", - "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", - "requires": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true - }, - "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, - "requires": { - "color-convert": "^1.9.0" - } - }, - "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" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha512-CJ17OoULEKXpA5pef3qLj5AxTJ6mSt7g84he2WIskKwqFO4T97d5V7Tadl0DYDk7qyUOQD5WlUlOMChaYrhxeA==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==" - }, - "xss": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/xss/-/xss-1.0.11.tgz", - "integrity": "sha512-EimjrjThZeK2MO7WKR9mN5ZC1CSqivSl55wvUK5EtU6acf0rzEE1pN+9ZDrFXJ82BRp3JL38pPE6S4o/rpp1zQ==", - "requires": { - "commander": "^2.20.3", - "cssfilter": "0.0.10" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - }, - "yamljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", - "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", - "requires": { - "argparse": "^1.0.7", - "glob": "^7.0.5" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "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" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - } - } - } -} diff --git a/package.json b/package.json index 40dd562f..0f56204a 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,9 @@ "main": "app.js", "scripts": { "start": "node app.js", - "lint": "standard", - "lint:fix": "standard --fix", + "dev": "nodemon app.js", + "lint": "prettier src/**/*.js", + "lint:fix": "prettier --write src/**/*.js", "init-es": "node src/init-es.js", "init-db": "node src/init-db.js", "sync-es": "node src/scripts/sync-es.js", @@ -27,27 +28,33 @@ "local:reset": "npm run init-es force && npm run init-db force" }, "author": "TCSCODER", - "license": "none", + "license": "MIT", "repository": "https://github.com/topcoder-platform/challenge-api", "devDependencies": { "chai": "^4.2.0", "chai-http": "^4.2.1", "mocha": "^6.1.4", "mocha-prepare": "^0.1.0", + "nodemon": "^2.0.20", "nyc": "^14.0.0", - "standard": "^12.0.1" + "prettier": "^2.8.1" }, "dependencies": { + "@grpc/grpc-js": "^1.8.12", + "@opensearch-project/opensearch": "^2.2.0", + "@topcoder-framework/domain-challenge": "^0.10.13", + "@topcoder-framework/lib-common": "^0.10.13", "aws-sdk": "^2.1145.0", "axios": "^0.19.0", - "axios-retry": "^3.3.1", + "axios-retry": "^3.4.0", "bluebird": "^3.5.1", "body-parser": "^1.15.1", "config": "^3.0.1", "cors": "^2.7.1", + "deep-equal": "^2.2.0", "dotenv": "^8.2.0", "dynamoose": "^1.11.1", - "elasticsearch": "^16.1.1", + "elasticsearch": "^16.7.3", "express": "^4.15.4", "express-fileupload": "^1.1.6", "express-interceptor": "^1.2.0", @@ -63,7 +70,7 @@ "tc-core-library-js": "appirio-tech/tc-core-library-js.git#v2.6.4", "topcoder-bus-api-wrapper": "topcoder-platform/tc-bus-api-wrapper.git", "uuid": "^3.3.2", - "winston": "^3.1.0", + "winston": "^3.8.2", "xss": "^1.0.8", "yamljs": "^0.3.0" }, @@ -76,9 +83,10 @@ ] }, "engines": { - "node": "14.x" + "node": "18.x" }, "volta": { - "node": "14.21.2" + "node": "18.12.1", + "yarn": "1.22.19" } } diff --git a/src/common/challenge-helper.js b/src/common/challenge-helper.js new file mode 100644 index 00000000..b6a3db22 --- /dev/null +++ b/src/common/challenge-helper.js @@ -0,0 +1,350 @@ +const challengeTypeService = require("../services/ChallengeTypeService"); +const challengeTrackService = require("../services/ChallengeTrackService"); +const timelineTemplateService = require("../services/TimelineTemplateService"); +const HttpStatus = require("http-status-codes"); +const _ = require("lodash"); +const errors = require("./errors"); +const config = require("config"); +const helper = require("./helper"); +const constants = require("../../app-constants"); +const axios = require("axios"); +const { getM2MToken } = require("./m2m-helper"); +const { hasAdminRole } = require("./role-helper"); +const { ensureAcessibilityToModifiedGroups } = require("./group-helper"); + +class ChallengeHelper { + /** + * @param {Object} challenge the challenge object + * @returns {Promise<{trackId, typeId}>} the challenge track and type ids + */ + async validateAndGetChallengeTypeAndTrack({ typeId, trackId, timelineTemplateId }) { + let challengeType; + if (typeId) { + challengeType = await challengeTypeService.getChallengeType(typeId); + } + + let challengeTrack; + if (trackId) { + challengeTrack = await challengeTrackService.getChallengeTrack(trackId); + } + + if (timelineTemplateId) { + const template = await timelineTemplateService.getTimelineTemplate(timelineTemplateId); + + if (!template.isActive) { + throw new errors.BadRequestError( + `The timeline template with id: ${timelineTemplateId} is inactive` + ); + } + } + + return { type: challengeType, track: challengeTrack }; + } + + /** + * Ensure project exist + * @param {String} projectId the project id + * @param {String} currentUser the user + */ + static async ensureProjectExist(projectId, currentUser) { + let token = await getM2MToken(); + const url = `${config.PROJECTS_API_URL}/${projectId}`; + try { + const res = await axios.get(url, { headers: { Authorization: `Bearer ${token}` } }); + if (currentUser.isMachine || hasAdminRole(currentUser)) { + return res.data; + } + if ( + _.get(res, "data.type") === "self-service" && + _.includes(config.SELF_SERVICE_WHITELIST_HANDLES, currentUser.handle.toLowerCase()) + ) { + return res.data; + } + if ( + !_.find( + _.get(res, "data.members", []), + (m) => _.toString(m.userId) === _.toString(currentUser.userId) + ) + ) { + throw new errors.ForbiddenError(`You don't have access to project with ID: ${projectId}`); + } + return res.data; + } catch (err) { + if (_.get(err, "response.status") === HttpStatus.NOT_FOUND) { + throw new errors.BadRequestError(`Project with id: ${projectId} doesn't exist`); + } else { + // re-throw other error + throw err; + } + } + } + + async validateCreateChallengeRequest(currentUser, challenge) { + // projectId is required for non self-service challenges + if (challenge.legacy.selfService == null && challenge.projectId == null) { + throw new errors.BadRequestError("projectId is required for non self-service challenges."); + } + + if (challenge.status === constants.challengeStatuses.Active) { + throw new errors.BadRequestError( + "You cannot create an Active challenge. Please create a Draft challenge and then change the status to Active." + ); + } + + helper.ensureNoDuplicateOrNullElements(challenge.tags, "tags"); + helper.ensureNoDuplicateOrNullElements(challenge.groups, "groups"); + // helper.ensureNoDuplicateOrNullElements(challenge.terms, 'terms') + // helper.ensureNoDuplicateOrNullElements(challenge.events, 'events') + + // check groups authorization + await helper.ensureAccessibleByGroupsAccess(currentUser, challenge); + } + + async validateChallengeUpdateRequest(currentUser, challenge, data) { + if (process.env.LOCAL != "true") { + await helper.ensureUserCanModifyChallenge(currentUser, challenge); + } + + helper.ensureNoDuplicateOrNullElements(data.tags, "tags"); + helper.ensureNoDuplicateOrNullElements(data.groups, "groups"); + + if (data.projectId) { + await ChallengeHelper.ensureProjectExist(data.projectId, currentUser); + } + + // check groups access to be updated group values + if (data.groups) { + await ensureAcessibilityToModifiedGroups(currentUser, data, challenge); + } + + // Ensure descriptionFormat is either 'markdown' or 'html' + if (data.descriptionFormat && !_.includes(["markdown", "html"], data.descriptionFormat)) { + throw new errors.BadRequestError("The property 'descriptionFormat' must be either 'markdown' or 'html'"); + } + + // Ensure unchangeable fields are not changed + if ( + _.get(challenge, "legacy.track") && + _.get(data, "legacy.track") && + _.get(challenge, "legacy.track") !== _.get(data, "legacy.track") + ) { + throw new errors.ForbiddenError("Cannot change legacy.track"); + } + + if ( + _.get(challenge, "trackId") && + _.get(data, "trackId") && + _.get(challenge, "trackId") !== _.get(data, "trackId") + ) { + throw new errors.ForbiddenError("Cannot change trackId"); + } + + if ( + _.get(challenge, "typeId") && + _.get(data, "typeId") && + _.get(challenge, "typeId") !== _.get(data, "typeId") + ) { + throw new errors.ForbiddenError("Cannot change typeId"); + } + + if ( + _.get(challenge, "legacy.pureV5Task") && + _.get(data, "legacy.pureV5Task") && + _.get(challenge, "legacy.pureV5Task") !== _.get(data, "legacy.pureV5Task") + ) { + throw new errors.ForbiddenError("Cannot change legacy.pureV5Task"); + } + + if ( + _.get(challenge, "legacy.pureV5") && + _.get(data, "legacy.pureV5") && + _.get(challenge, "legacy.pureV5") !== _.get(data, "legacy.pureV5") + ) { + throw new errors.ForbiddenError("Cannot change legacy.pureV5"); + } + + if ( + _.get(challenge, "legacy.selfService") && + _.get(data, "legacy.selfService") && + _.get(challenge, "legacy.selfService") !== _.get(data, "legacy.selfService") + ) { + throw new errors.ForbiddenError("Cannot change legacy.selfService"); + } + + if ( + (challenge.status === constants.challengeStatuses.Completed || + challenge.status === constants.challengeStatuses.Cancelled) && + data.status && + data.status !== challenge.status && + data.status !== constants.challengeStatuses.CancelledClientRequest + ) { + throw new errors.BadRequestError( + `Cannot change ${challenge.status} challenge status to ${data.status} status` + ); + } + + if ( + data.winners && + data.winners.length > 0 && + challenge.status !== constants.challengeStatuses.Completed && + data.status !== constants.challengeStatuses.Completed + ) { + throw new errors.BadRequestError( + `Cannot set winners for challenge with non-completed ${challenge.status} status` + ); + } + } + + sanitizeRepeatedFieldsInUpdateRequest(data) { + if (data.winners != null) { + data.winnerUpdate = { + winners: data.winners, + }; + delete data.winners; + } + + if (data.discussions != null) { + data.discussionUpdate = { + discussions: data.discussions, + }; + delete data.discussions; + } + + if (data.metadata != null) { + data.metadataUpdate = { + metadata: data.metadata, + }; + delete data.metadata; + } + + if (data.phases != null) { + data.phaseUpdate = { + phases: data.phases, + }; + delete data.phases; + } + + if (data.events != null) { + data.eventUpdate = { + events: data.events, + }; + delete data.events; + } + + if (data.terms != null) { + data.termUpdate = { + terms: data.terms, + }; + delete data.terms; + } + + if (data.prizeSets != null) { + data.prizeSetUpdate = { + prizeSets: data.prizeSets, + }; + delete data.prizeSets; + } + + if (data.tags != null) { + data.tagUpdate = { + tags: data.tags, + }; + delete data.tags; + } + + if (data.attachments != null) { + data.attachmentUpdate = { + attachments: data.attachments, + }; + delete data.attachments; + } + + if (data.groups != null) { + data.groupUpdate = { + groups: data.groups, + }; + delete data.groups; + } + + return data; + } + + enrichChallengeForResponse(challenge, track, type) { + if (challenge.phases && challenge.phases.length > 0) { + const registrationPhase = _.find(challenge.phases, (p) => p.name === "Registration"); + const submissionPhase = _.find(challenge.phases, (p) => p.name === "Submission"); + + challenge.currentPhase = challenge.phases + .slice() + .reverse() + .find((phase) => phase.isOpen); + + challenge.currentPhaseNames = _.map( + _.filter(challenge.phases, (p) => p.isOpen === true), + "name" + ); + + if (registrationPhase) { + challenge.registrationStartDate = + registrationPhase.actualStartDate || registrationPhase.scheduledStartDate; + challenge.registrationEndDate = + registrationPhase.actualEndDate || registrationPhase.scheduledEndDate; + } + if (submissionPhase) { + challenge.submissionStartDate = + submissionPhase.actualStartDate || submissionPhase.scheduledStartDate; + + challenge.submissionEndDate = + submissionPhase.actualEndDate || submissionPhase.scheduledEndDate; + } + } + + challenge.created = new Date(challenge.created).toISOString(); + challenge.updated = new Date(challenge.updated).toISOString(); + challenge.startDate = new Date(challenge.startDate).toISOString(); + challenge.endDate = new Date(challenge.endDate).toISOString(); + + if (track) { + challenge.track = track.name; + } + + if (type) { + challenge.type = type.name; + } + + challenge.metadata = challenge.metadata.map((m) => { + try { + m.value = JSON.stringify(JSON.parse(m.value)); // when we update how we index data, make this a JSON field + } catch (err) { + // do nothing + } + return m; + }); + } + + convertPrizeSetValuesToCents(prizeSets) { + prizeSets.forEach((prizeSet) => { + prizeSet.prizes.forEach((prize) => { + prize.amountInCents = prize.value * 100; + delete prize.value; + }); + }); + } + + convertPrizeSetValuesToDollars(prizeSets, overview) { + prizeSets.forEach((prizeSet) => { + prizeSet.prizes.forEach((prize) => { + if (prize.amountInCents != null) { + prize.value = prize.amountInCents / 100; + delete prize.amountInCents; + } + }); + }); + if (overview && overview.totalPrizesInCents) { + overview.totalPrizes = overview.totalPrizesInCents / 100; + delete overview.totalPrizesInCents; + } + } +} + +module.exports = new ChallengeHelper(); diff --git a/src/common/errors.js b/src/common/errors.js index 3b345883..e3b2040f 100644 --- a/src/common/errors.js +++ b/src/common/errors.js @@ -1,7 +1,7 @@ /** * This file defines application errors */ -const util = require('util') +const util = require("util"); /** * Helper function to create generic error object with http status code @@ -10,31 +10,31 @@ const util = require('util') * @returns {Function} the error constructor * @private */ -function createError (name, statusCode) { +function createError(name, statusCode) { /** * The error constructor * @param {String} message the error message * @param {String} [cause] the error cause * @constructor */ - function ErrorCtor (message, cause) { - Error.call(this) - Error.captureStackTrace(this) - this.message = message || name - this.cause = cause - this.httpStatus = statusCode + function ErrorCtor(message, cause) { + Error.call(this); + Error.captureStackTrace(this); + this.message = message || name; + this.cause = cause; + this.httpStatus = statusCode; } - util.inherits(ErrorCtor, Error) - ErrorCtor.prototype.name = name - return ErrorCtor + util.inherits(ErrorCtor, Error); + ErrorCtor.prototype.name = name; + return ErrorCtor; } module.exports = { - BadRequestError: createError('BadRequestError', 400), - UnauthorizedError: createError('UnauthorizedError', 401), - ForbiddenError: createError('ForbiddenError', 403), - NotFoundError: createError('NotFoundError', 404), - ConflictError: createError('ConflictError', 409), - ServiceUnavailableError: createError('ServiceUnavailableError', 503) -} + BadRequestError: createError("BadRequestError", 400), + UnauthorizedError: createError("UnauthorizedError", 401), + ForbiddenError: createError("ForbiddenError", 403), + NotFoundError: createError("NotFoundError", 404), + ConflictError: createError("ConflictError", 409), + ServiceUnavailableError: createError("ServiceUnavailableError", 503), +}; diff --git a/src/common/group-helper.js b/src/common/group-helper.js new file mode 100644 index 00000000..7ef2911d --- /dev/null +++ b/src/common/group-helper.js @@ -0,0 +1,36 @@ +const _ = require("lodash"); +const errors = require("./errors"); +const helper = require("./helper"); + +const { hasAdminRole } = require("./role-helper"); + +class GroupHelper { + /** + * Ensure the user can access the groups being updated to + * @param {Object} currentUser the user who perform operation + * @param {Object} data the challenge data to be updated + * @param {String} challenge the original challenge data + */ + async ensureAcessibilityToModifiedGroups(currentUser, data, challenge) { + const needToCheckForGroupAccess = !currentUser + ? true + : !currentUser.isMachine && !hasAdminRole(currentUser); + if (!needToCheckForGroupAccess) { + return; + } + const userGroups = await helper.getUserGroups(currentUser.userId); + const userGroupsIds = _.map(userGroups, (group) => group.id); + const updatedGroups = _.difference( + _.union(challenge.groups, data.groups), + _.intersection(challenge.groups, data.groups) + ); + const filtered = updatedGroups.filter((g) => !userGroupsIds.includes(g)); + if (filtered.length > 0) { + throw new errors.ForbiddenError( + "ensureAcessibilityToModifiedGroups :: You don't have access to this group!" + ); + } + } +} + +module.exports = new GroupHelper(); diff --git a/src/common/helper.js b/src/common/helper.js index cc8cdddd..e5228f09 100644 --- a/src/common/helper.js +++ b/src/common/helper.js @@ -1,76 +1,80 @@ /** * This file defines helper methods */ -const Joi = require('joi') -const _ = require('lodash') -const querystring = require('querystring') -const constants = require('../../app-constants') -const models = require('../models') -const errors = require('./errors') -const util = require('util') -const AWS = require('aws-sdk') -const config = require('config') -const m2mAuth = require('tc-core-library-js').auth.m2m -const m2m = m2mAuth(_.pick(config, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME'])) -const axios = require('axios') -const axiosRetry = require('axios-retry') -const busApi = require('topcoder-bus-api-wrapper') -const elasticsearch = require('elasticsearch') -const NodeCache = require('node-cache') -const HttpStatus = require('http-status-codes') -const xss = require('xss') -const logger = require('./logger') +const Joi = require("joi"); +const _ = require("lodash"); +const querystring = require("querystring"); +const constants = require("../../app-constants"); +const models = require("../models"); +const errors = require("./errors"); +const util = require("util"); +const AWS = require("aws-sdk"); +const config = require("config"); +const axios = require("axios"); +const axiosRetry = require("axios-retry"); +const busApi = require("topcoder-bus-api-wrapper"); +const NodeCache = require("node-cache"); +const HttpStatus = require("http-status-codes"); +const xss = require("xss"); +const logger = require("./logger"); + +const { Client: ESClient } = require("@opensearch-project/opensearch"); +const elasticsearch = require("elasticsearch"); + +const projectHelper = require("./project-helper"); +const m2mHelper = require("./m2m-helper"); +const { hasAdminRole } = require("./role-helper"); // Bus API Client -let busApiClient +let busApiClient; // Elasticsearch client -let esClient +let esClient; // validate ES refresh method -validateESRefreshMethod(config.ES.ES_REFRESH) +validateESRefreshMethod(config.ES.ES_REFRESH); AWS.config.update({ s3: config.AMAZON.S3_API_VERSION, // accessKeyId: config.AMAZON.AWS_ACCESS_KEY_ID, // secretAccessKey: config.AMAZON.AWS_SECRET_ACCESS_KEY, - region: config.AMAZON.AWS_REGION -}) -const s3 = new AWS.S3() + region: config.AMAZON.AWS_REGION, +}); +const s3 = new AWS.S3(); /** * Wrap async function to standard express function * @param {Function} fn the async function * @returns {Function} the wrapped function */ -function wrapExpress (fn) { +function wrapExpress(fn) { return function (req, res, next) { - fn(req, res, next).catch(next) - } + fn(req, res, next).catch(next); + }; } // Internal cache -const internalCache = new NodeCache({ stdTTL: config.INTERNAL_CACHE_TTL }) +const internalCache = new NodeCache({ stdTTL: config.INTERNAL_CACHE_TTL }); /** * Wrap all functions from object * @param obj the object (controller exports) * @returns {Object|Array} the wrapped object */ -function autoWrapExpress (obj) { +function autoWrapExpress(obj) { if (_.isArray(obj)) { - return obj.map(autoWrapExpress) + return obj.map(autoWrapExpress); } if (_.isFunction(obj)) { - if (obj.constructor.name === 'AsyncFunction') { - return wrapExpress(obj) + if (obj.constructor.name === "AsyncFunction") { + return wrapExpress(obj); } - return obj + return obj; } _.each(obj, (value, key) => { - obj[key] = autoWrapExpress(value) - }) - return obj + obj[key] = autoWrapExpress(value); + }); + return obj; } /** @@ -79,9 +83,9 @@ function autoWrapExpress (obj) { * @param {Number} page the page number * @returns {String} link for the page */ -function getPageLink (req, page) { - const q = _.assignIn({}, req.query, { page }) - return `${config.API_BASE_URL}${req.path}?${querystring.stringify(q)}` +function getPageLink(req, page) { + const q = _.assignIn({}, req.query, { page }); + return `${config.API_BASE_URL}${req.path}?${querystring.stringify(q)}`; } /** @@ -90,44 +94,32 @@ function getPageLink (req, page) { * @param {Object} res the HTTP response * @param {Object} result the operation result */ -function setResHeaders (req, res, result) { - const totalPages = Math.ceil(result.total / result.perPage) +function setResHeaders(req, res, result) { + const totalPages = Math.ceil(result.total / result.perPage); if (parseInt(result.page, 10) > 1) { - res.set('X-Prev-Page', parseInt(result.page, 10) - 1) + res.set("X-Prev-Page", parseInt(result.page, 10) - 1); } if (parseInt(result.page, 10) < totalPages) { - res.set('X-Next-Page', parseInt(result.page, 10) + 1) + res.set("X-Next-Page", parseInt(result.page, 10) + 1); } - res.set('X-Page', parseInt(result.page, 10)) - res.set('X-Per-Page', result.perPage) - res.set('X-Total', result.total) - res.set('X-Total-Pages', totalPages) + res.set("X-Page", parseInt(result.page, 10)); + res.set("X-Per-Page", result.perPage); + res.set("X-Total", result.total); + res.set("X-Total-Pages", totalPages); // set Link header if (totalPages > 0) { - let link = `<${getPageLink(req, 1)}>; rel="first", <${getPageLink(req, totalPages)}>; rel="last"` + let link = `<${getPageLink(req, 1)}>; rel="first", <${getPageLink( + req, + totalPages + )}>; rel="last"`; if (parseInt(result.page, 10) > 1) { - link += `, <${getPageLink(req, parseInt(result.page, 10) - 1)}>; rel="prev"` + link += `, <${getPageLink(req, parseInt(result.page, 10) - 1)}>; rel="prev"`; } if (parseInt(result.page, 10) < totalPages) { - link += `, <${getPageLink(req, parseInt(result.page, 10) + 1)}>; rel="next"` - } - res.set('Link', link) - } -} - -/** - * Check if the user has admin role - * @param {Object} authUser the user - */ -function hasAdminRole (authUser) { - if (authUser && authUser.roles) { - for (let i = 0; i < authUser.roles.length; i++) { - if (authUser.roles[i].toLowerCase() === constants.UserRoles.Admin.toLowerCase()) { - return true - } + link += `, <${getPageLink(req, parseInt(result.page, 10) + 1)}>; rel="next"`; } + res.set("Link", link); } - return false } /** @@ -136,16 +128,18 @@ function hasAdminRole (authUser) { * @returns {Object} the new object with removed properties * @private */ -function _sanitizeObject (obj) { +function _sanitizeObject(obj) { try { - return JSON.parse(JSON.stringify(obj, (name, value) => { - if (_.isArray(value) && value.length > 30) { - return `Array(${value.length})` - } - return value - })) + return JSON.parse( + JSON.stringify(obj, (name, value) => { + if (_.isArray(value) && value.length > 30) { + return `Array(${value.length})`; + } + return value; + }) + ); } catch (e) { - return obj + return obj; } } @@ -154,8 +148,8 @@ function _sanitizeObject (obj) { * @param {Object} obj the object * @returns {String} the string value */ -function toString (obj) { - return util.inspect(_sanitizeObject(obj), { breakLength: Infinity }) +function toString(obj) { + return util.inspect(_sanitizeObject(obj), { breakLength: Infinity }); } /** @@ -164,30 +158,30 @@ function toString (obj) { * @param {Array} source the array in which to search for the term * @param {Array | String} term the term to search */ -function checkIfExists (source, term) { - let terms +function checkIfExists(source, term) { + let terms; if (!_.isArray(source)) { - throw new Error('Source argument should be an array') + throw new Error("Source argument should be an array"); } - source = source.map(s => s.toLowerCase()) + source = source.map((s) => s.toLowerCase()); if (_.isString(term)) { - terms = term.toLowerCase().split(' ') + terms = term.toLowerCase().split(" "); } else if (_.isArray(term)) { - terms = term.map(t => t.toLowerCase()) + terms = term.map((t) => t.toLowerCase()); } else { - throw new Error('Term argument should be either a string or an array') + throw new Error("Term argument should be either a string or an array"); } for (let i = 0; i < terms.length; i++) { if (source.includes(terms[i])) { - return true + return true; } } - return false + return false; } /** @@ -196,19 +190,23 @@ function checkIfExists (source, term) { * @param {String} id The id value * @returns {Promise} */ -async function getById (modelName, id) { +async function getById(modelName, id) { return new Promise((resolve, reject) => { - models[modelName].query('id').eq(id).exec((err, result) => { - if (err) { - return reject(err) - } - if (result.length > 0) { - return resolve(result[0]) - } else { - return reject(new errors.NotFoundError(`${modelName} with id: ${id} doesn't exist`)) - } - }) - }) + models[modelName] + .query("id") + .eq(id) + .exec((err, result) => { + if (err) { + console.log("rejecting error", err); + return reject(err); + } + if (result.length > 0) { + return resolve(result[0]); + } else { + return reject(new errors.NotFoundError(`${modelName} with id: ${id} doesn't exist`)); + } + }); + }); } /** @@ -217,13 +215,13 @@ async function getById (modelName, id) { * @param {Array} ids The ids * @returns {Promise} the found entities */ -async function getByIds (modelName, ids) { - const entities = [] - const theIds = ids || [] +async function getByIds(modelName, ids) { + const entities = []; + const theIds = ids || []; for (const id of theIds) { - entities.push(await getById(modelName, id)) + entities.push(await getById(modelName, id)); } - return entities + return entities; } /** @@ -233,11 +231,11 @@ async function getByIds (modelName, ids) { * @param {String} value The attribute value to be validated * @returns {Promise} */ -async function validateDuplicate (modelName, name, value) { - const list = await scan(modelName) +async function validateDuplicate(modelName, name, value) { + const list = await scan(modelName); for (let i = 0; i < list.length; i++) { if (list[i][name] && String(list[i][name]).toLowerCase() === String(value).toLowerCase()) { - throw new errors.ConflictError(`${modelName} with ${name}: ${value} already exist`) + throw new errors.ConflictError(`${modelName} with ${name}: ${value} already exist`); } } } @@ -248,17 +246,17 @@ async function validateDuplicate (modelName, name, value) { * @param {Object} data The create data object * @returns {Promise} */ -async function create (modelName, data) { +async function create(modelName, data) { return new Promise((resolve, reject) => { - const dbItem = new models[modelName](data) + const dbItem = new models[modelName](data); dbItem.save((err) => { if (err) { - return reject(err) + return reject(err); } else { - return resolve(dbItem) + return resolve(dbItem); } - }) - }) + }); + }); } /** @@ -267,19 +265,19 @@ async function create (modelName, data) { * @param {Object} data The updated data object * @returns {Promise} */ -async function update (dbItem, data) { +async function update(dbItem, data) { Object.keys(data).forEach((key) => { - dbItem[key] = data[key] - }) + dbItem[key] = data[key]; + }); return new Promise((resolve, reject) => { dbItem.save((err) => { if (err) { - return reject(err) + return reject(err); } else { - return resolve(dbItem) + return resolve(dbItem); } - }) - }) + }); + }); } /** @@ -288,16 +286,16 @@ async function update (dbItem, data) { * @param {Object} scanParams The scan parameters object * @returns {Promise} */ -async function scan (modelName, scanParams) { +async function scan(modelName, scanParams) { return new Promise((resolve, reject) => { models[modelName].scan(scanParams).exec((err, result) => { if (err) { - return reject(err) + return reject(err); } else { - return resolve(result.count === 0 ? [] : result) + return resolve(result.count === 0 ? [] : result); } - }) - }) + }); + }); } /** @@ -306,15 +304,15 @@ async function scan (modelName, scanParams) { * @param {Object} scanParams The scan parameters object * @returns {Array} */ -async function scanAll (modelName, scanParams) { - let results = await models[modelName].scan(scanParams).exec() - let lastKey = results.lastKey +async function scanAll(modelName, scanParams) { + let results = await models[modelName].scan(scanParams).exec(); + let lastKey = results.lastKey; while (!_.isUndefined(results.lastKey)) { - const newResult = await models[modelName].scan(scanParams).startAt(lastKey).exec() - results = [...results, ...newResult] - lastKey = newResult.lastKey + const newResult = await models[modelName].scan(scanParams).startAt(lastKey).exec(); + results = [...results, ...newResult]; + lastKey = newResult.lastKey; } - return results + return results; } /** @@ -323,16 +321,16 @@ async function scanAll (modelName, scanParams) { * @param {String} value the value to test * @returns {Boolean} the match result */ -function partialMatch (filter, value) { +function partialMatch(filter, value) { if (filter) { if (value) { - const filtered = xss(filter) - return _.toLower(value).includes(_.toLower(filtered)) + const filtered = xss(filter); + return _.toLower(value).includes(_.toLower(filtered)); } else { - return false + return false; } } else { - return true + return true; } } @@ -342,12 +340,12 @@ function partialMatch (filter, value) { * @param {String} key the key name * @return {Promise} promise resolved to downloaded data */ -async function downloadFromFileStack (url) { - const res = await axios.get(url) +async function downloadFromFileStack(url) { + const res = await axios.get(url); return { data: res.data, - mimetype: _.get(res, `headers['content-type']`, 'application/json') - } + mimetype: _.get(res, `headers['content-type']`, "application/json"), + }; } /** @@ -356,12 +354,12 @@ async function downloadFromFileStack (url) { * @param {String} key the key name * @return {Promise} promise resolved to downloaded data */ -async function downloadFromS3 (bucket, key) { - const file = await s3.getObject({ Bucket: bucket, Key: key }).promise() +async function downloadFromS3(bucket, key) { + const file = await s3.getObject({ Bucket: bucket, Key: key }).promise(); return { data: file.Body, - mimetype: file.ContentType - } + mimetype: file.ContentType, + }; } /** @@ -370,16 +368,8 @@ async function downloadFromS3 (bucket, key) { * @param {String} key the key name * @return {Promise} promise resolved to deleted data */ -async function deleteFromS3 (bucket, key) { - return s3.deleteObject({ Bucket: bucket, Key: key }).promise() -} - -/** - * Get M2M token. - * @returns {Promise} the M2M token - */ -async function getM2MToken () { - return m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET) +async function deleteFromS3(bucket, key) { + return s3.deleteObject({ Bucket: bucket, Key: key }).promise(); } /** @@ -387,24 +377,26 @@ async function getM2MToken () { * @param {String} challengeId the challenge id * @returns {Promise} the challenge resources */ -async function getChallengeResources (challengeId) { - const token = await getM2MToken() - const perPage = 100 - let page = 1 - let result = [] +async function getChallengeResources(challengeId) { + const token = await m2mHelper.getM2MToken(); + const perPage = 100; + let page = 1; + let result = []; while (true) { - const url = `${config.RESOURCES_API_URL}?challengeId=${challengeId}&perPage=${perPage}&page=${page}` - const res = await axios.get(url, { headers: { Authorization: `Bearer ${token}` } }) + const url = `${config.RESOURCES_API_URL}?challengeId=${challengeId}&perPage=${perPage}&page=${page}`; + const res = await axios.get(url, { + headers: { Authorization: `Bearer ${token}` }, + }); if (!res.data || res.data.length === 0) { - break + break; } - result = result.concat(res.data) - page += 1 - if (res.headers['x-total-pages'] && page > Number(res.headers['x-total-pages'])) { - break + result = result.concat(res.data); + page += 1; + if (res.headers["x-total-pages"] && page > Number(res.headers["x-total-pages"])) { + break; } } - return result + return result; } /** @@ -413,35 +405,42 @@ async function getChallengeResources (challengeId) { * @param {String} memberHandle the user's member handle * @param {String} roleId the resource role ID to assign */ -async function createResource (challengeId, memberHandle, roleId) { - const token = await getM2MToken() +async function createResource(challengeId, memberHandle, roleId) { + const token = await m2mHelper.getM2MToken(); const userObj = { challengeId, memberHandle, - roleId - } - const url = `${config.RESOURCES_API_URL}` - const res = await axios.post(url, userObj, { headers: { Authorization: `Bearer ${token}` } }) - return res || false + roleId, + }; + const url = `${config.RESOURCES_API_URL}`; + const res = await axios.post(url, userObj, { + headers: { Authorization: `Bearer ${token}` }, + }); + return res || false; } -function exponentialDelay (retryNumber = 0) { - const delay = Math.pow(2, retryNumber) * 200 - const randomSum = delay * 0.2 * Math.random() // 0-20% of the delay - return delay + randomSum +function exponentialDelay(retryNumber = 0) { + const delay = Math.pow(2, retryNumber) * 200; + const randomSum = delay * 0.2 * Math.random(); // 0-20% of the delay + return delay + randomSum; } axiosRetry(axios, { retries: `${config.AXIOS_RETRIES}`, // number of retries retryCondition: (e) => { - return e.config.url.indexOf('v5/projects') > 0 && - (axiosRetry.isNetworkOrIdempotentRequestError(e) || e.response.status === HttpStatus.TOO_MANY_REQUESTS) + return ( + e.config.url.indexOf("v5/projects") > 0 && + (axiosRetry.isNetworkOrIdempotentRequestError(e) || + e.response.status === HttpStatus.TOO_MANY_REQUESTS) + ); }, onRetry: (retryCount, error, requestConfig) => - logger.info(`${error.message} while calling: ${requestConfig.url} - retry count: ${retryCount}`), - retryDelay: exponentialDelay -}) + logger.info( + `${error.message} while calling: ${requestConfig.url} - retry count: ${retryCount}` + ), + retryDelay: exponentialDelay, +}); /** * Create Project @@ -451,73 +450,78 @@ axiosRetry(axios, { * @param {String} token The token * @returns */ -async function createSelfServiceProject (name, description, type, token) { +async function createSelfServiceProject(name, description, type) { const projectObj = { name, description, - type - } - const url = `${config.PROJECTS_API_URL}` - const res = await axios.post(url, projectObj, { headers: { Authorization: `Bearer ${token}` } }) - return _.get(res, 'data.id') + type, + }; + + const token = await m2mHelper.getM2MToken(); + const url = `${config.PROJECTS_API_URL}`; + const res = await axios.post(url, projectObj, { + headers: { Authorization: `Bearer ${token}` }, + }); + + return _.get(res, "data.id"); } /** * Get project id by roundId * @param {String} roundId the round id */ -async function getProjectIdByRoundId (roundId) { - const url = `${config.CHALLENGE_MIGRATION_APP_URL}/getChallengeProjectId/${roundId}` - const res = await axios.get(url) - return _.get(res, 'data.projectId') +async function getProjectIdByRoundId(roundId) { + const url = `${config.CHALLENGE_MIGRATION_APP_URL}/getChallengeProjectId/${roundId}`; + const res = await axios.get(url); + return _.get(res, "data.projectId"); } /** * Get project payment * @param {String} projectId the project id */ -async function getProjectPayment (projectId) { - const token = await getM2MToken() - const url = `${config.CUSTOMER_PAYMENTS_URL}` +async function getProjectPayment(projectId) { + const token = await m2mHelper.getM2MToken(); + const url = `${config.CUSTOMER_PAYMENTS_URL}`; const res = await axios.get(url, { headers: { Authorization: `Bearer ${token}` }, params: { referenceId: projectId, - reference: 'project' - } - }) - const [payment] = res.data - return payment + reference: "project", + }, + }); + const [payment] = res.data; + return payment; } /** * Charge payment * @param {String} paymentId the payment ID */ -async function capturePayment (paymentId) { - const token = await getM2MToken() - const url = `${config.CUSTOMER_PAYMENTS_URL}/${paymentId}/charge` - logger.info(`Calling: ${url} to capture payment`) - const res = await axios.patch(url, {}, { headers: { Authorization: `Bearer ${token}` } }) - logger.debug(`Payment API Response: ${JSON.stringify(res.data, null, 2)}`) - if (res.data.status !== 'succeeded') { - throw new Error(`Failed to charge payment. Current status: ${res.data.status}`) +async function capturePayment(paymentId) { + const token = await m2mHelper.getM2MToken(); + const url = `${config.CUSTOMER_PAYMENTS_URL}/${paymentId}/charge`; + logger.info(`Calling: ${url} to capture payment`); + const res = await axios.patch(url, {}, { headers: { Authorization: `Bearer ${token}` } }); + logger.debug(`Payment API Response: ${JSON.stringify(res.data, null, 2)}`); + if (res.data.status !== "succeeded") { + throw new Error(`Failed to charge payment. Current status: ${res.data.status}`); } - return res.data + return res.data; } /** * Cancel payment * @param {String} paymentId the payment ID */ -async function cancelPayment (paymentId) { - const token = await getM2MToken() - const url = `${config.CUSTOMER_PAYMENTS_URL}/${paymentId}/cancel` - const res = await axios.patch(url, {}, { headers: { Authorization: `Bearer ${token}` } }) - if (res.data.status !== 'canceled') { - throw new Error(`Failed to cancel payment. Current status: ${res.data.status}`) +async function cancelPayment(paymentId) { + const token = await m2mHelper.getM2MToken(); + const url = `${config.CUSTOMER_PAYMENTS_URL}/${paymentId}/cancel`; + const res = await axios.patch(url, {}, { headers: { Authorization: `Bearer ${token}` } }); + if (res.data.status !== "canceled") { + throw new Error(`Failed to cancel payment. Current status: ${res.data.status}`); } - return res.data + return res.data; } /** @@ -526,30 +530,34 @@ async function cancelPayment (paymentId) { * @param {String} cancelReason the cancel reasonn * @param {Object} currentUser the current user */ -async function cancelProject (projectId, cancelReason, currentUser) { - let payment = await getProjectPayment(projectId) - const project = await ensureProjectExist(projectId, currentUser) - if (project.status === 'cancelled') return // already canceled +async function cancelProject(projectId, cancelReason, currentUser) { + let payment = await getProjectPayment(projectId); + const project = await projectHelper.getProject(projectId, currentUser); + if (project.status === "cancelled") return; // already canceled try { - payment = await cancelPayment(payment.id) + payment = await cancelPayment(payment.id); } catch (e) { - logger.debug(`Failed to cancel payment with error: ${e.message}`) + logger.debug(`Failed to cancel payment with error: ${e.message}`); } - const token = await getM2MToken() - const url = `${config.PROJECTS_API_URL}/${projectId}` - await axios.patch(url, { - cancelReason, - status: 'cancelled', - details: { - ...project.details, - paymentProvider: config.DEFAULT_PAYMENT_PROVIDER, - paymentId: payment.id, - paymentIntentId: payment.paymentIntentId, - paymentAmount: payment.amount, - paymentCurrency: payment.currency, - paymentStatus: payment.status - } - }, { headers: { Authorization: `Bearer ${token}` } }) + const token = await m2mHelper.getM2MToken(); + const url = `${config.PROJECTS_API_URL}/${projectId}`; + await axios.patch( + url, + { + cancelReason, + status: "cancelled", + details: { + ...project.details, + paymentProvider: config.DEFAULT_PAYMENT_PROVIDER, + paymentId: payment.id, + paymentIntentId: payment.paymentIntentId, + paymentAmount: payment.amount, + paymentCurrency: payment.currency, + paymentStatus: payment.status, + }, + }, + { headers: { Authorization: `Bearer ${token}` } } + ); } /** @@ -557,41 +565,49 @@ async function cancelProject (projectId, cancelReason, currentUser) { * @param {String} projectId the project id * @param {Object} currentUser the current user */ -async function activateProject (projectId, currentUser, name, description) { - let payment - let project +async function activateProject(projectId, currentUser, name, description) { + let payment; + let project; try { - payment = await getProjectPayment(projectId) - project = await ensureProjectExist(projectId, currentUser) - if (payment.status !== 'succeeded') { - payment = await capturePayment(payment.id) + payment = await getProjectPayment(projectId); + project = await projectHelper.getProject(projectId, currentUser); + if (payment.status !== "succeeded") { + payment = await capturePayment(payment.id); } } catch (e) { - logger.debug(e) - logger.debug(`Failed to charge payment ${payment.id} with error: ${e.message}`) - await cancelProject(projectId, `Failed to charge payment ${payment.id} with error: ${e.message}`, currentUser) - throw new Error(`Failed to charge payment ${payment.id} with error: ${e.message}`) + logger.debug(e); + logger.debug(`Failed to charge payment ${payment.id} with error: ${e.message}`); + await cancelProject( + projectId, + `Failed to charge payment ${payment.id} with error: ${e.message}`, + currentUser + ); + throw new Error(`Failed to charge payment ${payment.id} with error: ${e.message}`); } - const token = await getM2MToken() - const url = `${config.PROJECTS_API_URL}/${projectId}` - const res = await axios.patch(url, { - name, - description, - status: 'active', - details: { - ...project.details, - paymentProvider: config.DEFAULT_PAYMENT_PROVIDER, - paymentId: payment.id, - paymentIntentId: payment.paymentIntentId, - paymentAmount: payment.amount, - paymentCurrency: payment.currency, - paymentStatus: payment.status - } - }, { headers: { Authorization: `Bearer ${token}` } }) - - if (res.data && res.data.status === 'reviewed') { + const token = await m2mHelper.getM2MToken(); + const url = `${config.PROJECTS_API_URL}/${projectId}`; + const res = await axios.patch( + url, + { + name, + description, + status: "active", + details: { + ...project.details, + paymentProvider: config.DEFAULT_PAYMENT_PROVIDER, + paymentId: payment.id, + paymentIntentId: payment.paymentIntentId, + paymentAmount: payment.amount, + paymentCurrency: payment.currency, + paymentStatus: payment.status, + }, + }, + { headers: { Authorization: `Bearer ${token}` } } + ); + + if (res.data && res.data.status === "reviewed") { // auto activate if the project goes in reviewed state - await activateProject(projectId, currentUser, name, description) + await activateProject(projectId, currentUser, name, description); } } @@ -601,33 +617,40 @@ async function activateProject (projectId, currentUser, name, description) { * @param {*} workItemPlannedEndDate the planned end date of the work item * @param {*} currentUser the current user */ -async function updateSelfServiceProjectInfo (projectId, workItemPlannedEndDate, currentUser) { - const project = await ensureProjectExist(projectId, currentUser) - const payment = await getProjectPayment(projectId) - const token = await getM2MToken() - const url = `${config.PROJECTS_API_URL}/${projectId}` - await axios.patch(url, { - details: { - ...project.details, - paymentProvider: config.DEFAULT_PAYMENT_PROVIDER, - paymentId: payment.id, - paymentIntentId: payment.paymentIntentId, - paymentAmount: payment.amount, - paymentCurrency: payment.currency, - paymentStatus: payment.status, - workItemPlannedEndDate - } - }, { headers: { Authorization: `Bearer ${token}` } }) +async function updateSelfServiceProjectInfo(projectId, workItemPlannedEndDate, currentUser) { + const project = await projectHelper.getProject(projectId, currentUser); + const payment = await getProjectPayment(projectId); + const token = await m2mHelper.getM2MToken(); + const url = `${config.PROJECTS_API_URL}/${projectId}`; + + await axios.patch( + url, + { + details: { + ...project.details, + paymentProvider: config.DEFAULT_PAYMENT_PROVIDER, + paymentId: payment.id, + paymentIntentId: payment.paymentIntentId, + paymentAmount: payment.amount, + paymentCurrency: payment.currency, + paymentStatus: payment.status, + workItemPlannedEndDate, + }, + }, + { headers: { Authorization: `Bearer ${token}` } } + ); } /** * Get resource roles * @returns {Promise} the challenge resources */ -async function getResourceRoles () { - const token = await getM2MToken() - const res = await axios.get(config.RESOURCE_ROLES_API_URL, { headers: { Authorization: `Bearer ${token}` } }) - return res.data || [] +async function getResourceRoles() { + const token = await m2mHelper.getM2MToken(); + const res = await axios.get(config.RESOURCE_ROLES_API_URL, { + headers: { Authorization: `Bearer ${token}` }, + }); + return res.data || []; } /** @@ -635,11 +658,20 @@ async function getResourceRoles () { * @param {String} challengeId the challenge UUID * @param {String} userId the user ID */ -async function userHasFullAccess (challengeId, userId) { - const resourceRoles = await getResourceRoles() - const rolesWithFullAccess = _.map(_.filter(resourceRoles, r => r.fullWriteAccess), 'id') - const challengeResources = await getChallengeResources(challengeId) - return _.filter(challengeResources, r => _.toString(r.memberId) === _.toString(userId) && _.includes(rolesWithFullAccess, r.roleId)).length > 0 +async function userHasFullAccess(challengeId, userId) { + const resourceRoles = await getResourceRoles(); + const rolesWithFullAccess = _.map( + _.filter(resourceRoles, (r) => r.fullWriteAccess), + "id" + ); + const challengeResources = await getChallengeResources(challengeId); + return ( + _.filter( + challengeResources, + (r) => + _.toString(r.memberId) === _.toString(userId) && _.includes(rolesWithFullAccess, r.roleId) + ).length > 0 + ); } /** @@ -647,11 +679,11 @@ async function userHasFullAccess (challengeId, userId) { * @param {String} userId the user id * @returns {Promise} the user groups */ -async function getUserGroups (userId) { - const token = await getM2MToken() - let allGroups = [] +async function getUserGroups(userId) { + const token = await m2mHelper.getM2MToken(); + let allGroups = []; // get search is paginated, we need to get all pages' data - let page = 1 + let page = 1; while (true) { const result = await axios.get(config.GROUPS_API_URL, { headers: { Authorization: `Bearer ${token}` }, @@ -659,20 +691,20 @@ async function getUserGroups (userId) { page, perPage: 5000, memberId: userId, - membershipType: 'user' - } - }) - const groups = result.data || [] + membershipType: "user", + }, + }); + const groups = result.data || []; if (groups.length === 0) { - break + break; } - allGroups = allGroups.concat(groups) - page += 1 - if (result.headers['x-total-pages'] && page > Number(result.headers['x-total-pages'])) { - break + allGroups = allGroups.concat(groups); + page += 1; + if (result.headers["x-total-pages"] && page > Number(result.headers["x-total-pages"])) { + break; } } - return allGroups + return allGroups; } /** @@ -680,16 +712,16 @@ async function getUserGroups (userId) { * @param {String} userId the user id * @returns {Promise} the user groups */ -async function getCompleteUserGroupTreeIds (userId) { - const token = await getM2MToken() +async function getCompleteUserGroupTreeIds(userId) { + const token = await m2mHelper.getM2MToken(); const result = await axios.get(`${config.GROUPS_API_URL}/memberGroups/${userId}`, { headers: { Authorization: `Bearer ${token}` }, params: { - uuid: true - } - }) + uuid: true, + }, + }); - return result.data || [] + return result.data || []; } /** @@ -697,16 +729,16 @@ async function getCompleteUserGroupTreeIds (userId) { * @param {String} groupId the group ID * @returns {Array} an array with the groups ID and the IDs of all subGroups */ -async function expandWithSubGroups (groupId) { - const token = await getM2MToken() +async function expandWithSubGroups(groupId) { + const token = await m2mHelper.getM2MToken(); const result = await axios.get(`${config.GROUPS_API_URL}/${groupId}`, { headers: { Authorization: `Bearer ${token}` }, params: { - includeSubGroups: true - } - }) - const groups = result.data || {} - return [groupId, ..._.map(_.get(groups, 'subGroups', []), 'id')] + includeSubGroups: true, + }, + }); + const groups = result.data || {}; + return [groupId, ..._.map(_.get(groups, "subGroups", []), "id")]; } /** @@ -714,26 +746,26 @@ async function expandWithSubGroups (groupId) { * @param {String} groupId the group ID * @returns {Array} an array with the group ID and the IDs of all parent groups up the chain */ -async function expandWithParentGroups (groupId) { - const token = await getM2MToken() +async function expandWithParentGroups(groupId) { + const token = await m2mHelper.getM2MToken(); const result = await axios.get(`${config.GROUPS_API_URL}/${groupId}`, { headers: { Authorization: `Bearer ${token}` }, params: { includeParentGroup: true, - oneLevel: false - } - }) + oneLevel: false, + }, + }); - const ids = [] + const ids = []; const extractIds = (group) => { - ids.push(group.id) - _.each(_.get(group, 'parentGroups', []), (parent) => { - extractIds(parent) - }) - } + ids.push(group.id); + _.each(_.get(group, "parentGroups", []), (parent) => { + extractIds(parent); + }); + }; - extractIds(result.data || {}) - return ids + extractIds(result.data || {}); + return ids; } /** @@ -741,15 +773,15 @@ async function expandWithParentGroups (groupId) { * @param {Array} arr the array to check * @param {String} name the array name */ -function ensureNoDuplicateOrNullElements (arr, name) { - const a = arr || [] +function ensureNoDuplicateOrNullElements(arr, name) { + const a = arr || []; for (let i = 0; i < a.length; i += 1) { if (_.isNil(a[i])) { - throw new errors.BadRequestError(`There is null element for ${name}.`) + throw new errors.BadRequestError(`There is null element for ${name}.`); } for (let j = i + 1; j < a.length; j += 1) { if (a[i] === a[j]) { - throw new errors.BadRequestError(`There are duplicate elements (${a[i]}) for ${name}.`) + throw new errors.BadRequestError(`There are duplicate elements (${a[i]}) for ${name}.`); } } } @@ -759,16 +791,24 @@ function ensureNoDuplicateOrNullElements (arr, name) { * Get Bus API Client * @return {Object} Bus API Client Instance */ -function getBusApiClient () { +function getBusApiClient() { // if there is no bus API client instance, then create a new instance if (!busApiClient) { - busApiClient = busApi(_.pick(config, - ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME', - 'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'BUSAPI_URL', - 'KAFKA_ERROR_TOPIC', 'AUTH0_PROXY_SERVER_URL'])) + busApiClient = busApi( + _.pick(config, [ + "AUTH0_URL", + "AUTH0_AUDIENCE", + "TOKEN_CACHE_TIME", + "AUTH0_CLIENT_ID", + "AUTH0_CLIENT_SECRET", + "BUSAPI_URL", + "KAFKA_ERROR_TOPIC", + "AUTH0_PROXY_SERVER_URL", + ]) + ); } - return busApiClient + return busApiClient; } /** @@ -777,90 +817,70 @@ function getBusApiClient () { * @param {Object} payload the event payload * @param {Object} options the extra options to the message */ -async function postBusEvent (topic, payload, options = {}) { - const client = getBusApiClient() +async function postBusEvent(topic, payload, options = {}) { + const client = getBusApiClient(); const message = { topic, originator: constants.EVENT_ORIGINATOR, timestamp: new Date().toISOString(), - 'mime-type': constants.EVENT_MIME_TYPE, - payload - } + "mime-type": constants.EVENT_MIME_TYPE, + payload, + }; if (options.key) { - message.key = options.key + message.key = options.key; } - await client.postEvent(message) + await client.postEvent(message); } /** * Get ES Client * @return {Object} Elasticsearch Client Instance */ -function getESClient () { +function getESClient() { if (esClient) { - return esClient - } - const esHost = config.get('ES.HOST') - // AWS ES configuration is different from other providers - if (/.*amazonaws.*/.test(esHost)) { - esClient = elasticsearch.Client({ - apiVersion: config.get('ES.API_VERSION'), - hosts: esHost, - connectionClass: require('http-aws-es'), // eslint-disable-line global-require - amazonES: { - region: config.get('AMAZON.AWS_REGION'), - credentials: new AWS.EnvironmentCredentials('AWS') - } - }) - } else { - esClient = new elasticsearch.Client({ - apiVersion: config.get('ES.API_VERSION'), - hosts: esHost - }) + return esClient; } - return esClient -} - -/** - * Ensure project exist - * @param {String} projectId the project id - * @param {String} currentUser the user - */ -async function ensureProjectExist (projectId, currentUser) { - let token = await getM2MToken() - const url = `${config.PROJECTS_API_URL}/${projectId}` - try { - const res = await axios.get(url, { headers: { Authorization: `Bearer ${token}` } }) - if (currentUser.isMachine || hasAdminRole(currentUser)) { - return res.data - } - if (_.get(res, 'data.type') === 'self-service' && _.includes(config.SELF_SERVICE_WHITELIST_HANDLES, currentUser.handle.toLowerCase())) { - return res.data - } - if (!_.find(_.get(res, 'data.members', []), m => _.toString(m.userId) === _.toString(currentUser.userId))) { - throw new errors.ForbiddenError(`You don't have access to project with ID: ${projectId}`) - } - return res.data - } catch (err) { - if (_.get(err, 'response.status') === HttpStatus.NOT_FOUND) { - throw new errors.BadRequestError(`Project with id: ${projectId} doesn't exist`) + const esHost = config.get("ES.HOST"); + + if (config.get("ES.OPENSEARCH") == "false") { + if (/.*amazonaws.*/.test(esHost)) { + esClient = elasticsearch.Client({ + apiVersion: config.get("ES.API_VERSION"), + hosts: esHost, + connectionClass: require("http-aws-es"), // eslint-disable-line global-require + amazonES: { + region: config.get("AMAZON.AWS_REGION"), + credentials: new AWS.EnvironmentCredentials("AWS"), + }, + }); } else { - // re-throw other error - throw err + esClient = new elasticsearch.Client({ + apiVersion: config.get("ES.API_VERSION"), + hosts: esHost, + }); } + } else { + esClient = new ESClient({ + node: esHost, + ssl: { + rejectUnauthorized: false, + }, + }); } + + return esClient; } /** * Calculates challenge end date based on its phases * @param {any} challenge */ -function calculateChallengeEndDate (challenge, data) { +function calculateChallengeEndDate(challenge, data) { if (!data) { - data = challenge + data = challenge; } - let lastPhase = data.phases[data.phases.length - 1] - return lastPhase.actualEndDate || lastPhase.scheduledEndDate + let lastPhase = data.phases[data.phases.length - 1]; + return lastPhase.actualEndDate || lastPhase.scheduledEndDate; // let phase = data.phases[data.phases.length - 1] // if (!phase || (!data.startDate && !challenge.startDate)) { // return data.startDate || challenge.startDate @@ -882,36 +902,40 @@ function calculateChallengeEndDate (challenge, data) { * @param {Number} memberId the member id * @returns {Promise} an array of challenge ids represents challenges that given member has access to. */ -async function listChallengesByMember (memberId) { - const token = await getM2MToken() - let allIds = [] +async function listChallengesByMember(memberId) { + const token = await m2mHelper.getM2MToken(); + let allIds = []; // get search is paginated, we need to get all pages' data - let page = 1 + let page = 1; while (true) { - let result = {} + let result = {}; try { result = await axios.get(`${config.RESOURCES_API_URL}/${memberId}/challenges`, { headers: { Authorization: `Bearer ${token}` }, params: { page, - perPage: 10000 - } - }) + perPage: 10000, + }, + }); } catch (e) { // only log the error but don't throw it, so the following logic can still be executed. - logger.debug(`Failed to get challenges that accessible to the memberId ${memberId}`, e) + logger.debug(`Failed to get challenges that accessible to the memberId ${memberId}`, e); } - const ids = result.data || [] + const ids = result.data || []; if (ids.length === 0) { - break + break; } - allIds = allIds.concat(ids) - page += 1 - if (result.headers && result.headers['x-total-pages'] && page > Number(result.headers['x-total-pages'])) { - break + allIds = allIds.concat(ids); + page += 1; + if ( + result.headers && + result.headers["x-total-pages"] && + page > Number(result.headers["x-total-pages"]) + ) { + break; } } - return allIds + return allIds; } /** @@ -920,22 +944,25 @@ async function listChallengesByMember (memberId) { * @param {String} id the challenge id * @returns {Promise} an array of resources. */ -async function listResourcesByMemberAndChallenge (memberId, challengeId) { - const token = await getM2MToken() - let response = {} +async function listResourcesByMemberAndChallenge(memberId, challengeId) { + const token = await m2mHelper.getM2MToken(); + let response = {}; try { response = await axios.get(config.RESOURCES_API_URL, { headers: { Authorization: `Bearer ${token}` }, params: { memberId, - challengeId - } - }) + challengeId, + }, + }); } catch (e) { - logger.debug(`Failed to get resources on challenge ${challengeId} that memberId ${memberId} has`, e) + logger.debug( + `Failed to get resources on challenge ${challengeId} that memberId ${memberId} has`, + e + ); } - const result = response.data || [] - return result + const result = response.data || []; + return result; } /** @@ -944,9 +971,9 @@ async function listResourcesByMemberAndChallenge (memberId, challengeId) { * @param {String} method method to be tested * @returns {String} method valid method */ -async function validateESRefreshMethod (method) { - Joi.attempt(method, Joi.string().label('ES_REFRESH').valid(['true', 'false', 'wait_for'])) - return method +async function validateESRefreshMethod(method) { + Joi.attempt(method, Joi.string().label("ES_REFRESH").valid(["true", "false", "wait_for"])); + return method; } /** @@ -955,51 +982,20 @@ async function validateESRefreshMethod (method) { * @param {Number} projectId The id of the project for which to get the default terms of use * @returns {Promise>} An array containing the ids of the default project terms of use */ -async function getProjectDefaultTerms (projectId) { - const token = await getM2MToken() - const projectUrl = `${config.PROJECTS_API_URL}/${projectId}` - try { - const res = await axios.get(projectUrl, { headers: { Authorization: `Bearer ${token}` } }) - return res.data.terms || [] - } catch (err) { - if (_.get(err, 'response.status') === HttpStatus.NOT_FOUND) { - throw new errors.BadRequestError(`Project with id: ${projectId} doesn't exist`) - } else { - // re-throw other error - throw err - } - } -} - -/** - * This functions gets the default billing account for a given project id - * - * @param {Number} projectId The id of the project for which to get the default terms of use - * @returns {Promise} The billing account ID - */ -async function getProjectBillingInformation (projectId) { - const token = await getM2MToken() - const projectUrl = `${config.PROJECTS_API_URL}/${projectId}/billingAccount` +async function getProjectDefaultTerms(projectId) { + const token = await m2mHelper.getM2MToken(); + const projectUrl = `${config.PROJECTS_API_URL}/${projectId}`; try { - const res = await axios.get(projectUrl, { headers: { Authorization: `Bearer ${token}` } }) - let markup = _.get(res, 'data.markup', null) ? _.toNumber(_.get(res, 'data.markup', null)) : null - if (markup && markup > 0) { - // TODO - Hack to change int returned from api to decimal - markup = markup / 100 - } - return { - billingAccountId: _.get(res, 'data.tcBillingAccountId', null), - markup - } + const res = await axios.get(projectUrl, { + headers: { Authorization: `Bearer ${token}` }, + }); + return res.data.terms || []; } catch (err) { - if (_.get(err, 'response.status') === HttpStatus.NOT_FOUND) { - return { - billingAccountId: null, - markup: null - } + if (_.get(err, "response.status") === HttpStatus.NOT_FOUND) { + throw new errors.BadRequestError(`Project with id: ${projectId} doesn't exist`); } else { // re-throw other error - throw err + throw err; } } } @@ -1010,25 +1006,29 @@ async function getProjectBillingInformation (projectId) { * * @param {Array} terms The array of terms {id, roleId} to retrieve from terms API */ -async function validateChallengeTerms (terms = []) { - const listOfTerms = [] - const token = await getM2MToken() +async function validateChallengeTerms(terms = []) { + const listOfTerms = []; + const token = await m2mHelper.getM2MToken(); for (let term of terms) { // Get the terms details from the API try { - await axios.get(`${config.TERMS_API_URL}/${term.id}`, { headers: { Authorization: `Bearer ${token}` } }) - listOfTerms.push(term) + await axios.get(`${config.TERMS_API_URL}/${term.id}`, { + headers: { Authorization: `Bearer ${token}` }, + }); + listOfTerms.push(term); } catch (e) { - if (_.get(e, 'response.status') === HttpStatus.NOT_FOUND) { - throw new errors.BadRequestError(`Terms of use identified by the id ${term.id} does not exist`) + if (_.get(e, "response.status") === HttpStatus.NOT_FOUND) { + throw new errors.BadRequestError( + `Terms of use identified by the id ${term.id} does not exist` + ); } else { // re-throw other error - throw e + throw e; } } } - return listOfTerms + return listOfTerms; } /** @@ -1037,28 +1037,37 @@ async function validateChallengeTerms (terms = []) { * @param {Array} challenges the challenges to filter * @returns {Array} the challenges that can be accessed by current user */ -async function _filterChallengesByGroupsAccess (currentUser, challenges) { - const res = [] - const needToCheckForGroupAccess = !currentUser ? true : !currentUser.isMachine && !hasAdminRole(currentUser) - if (!needToCheckForGroupAccess) return challenges +async function _filterChallengesByGroupsAccess(currentUser, challenges) { + const res = []; + const needToCheckForGroupAccess = !currentUser + ? true + : !currentUser.isMachine && !hasAdminRole(currentUser); + if (!needToCheckForGroupAccess) return challenges; - let userGroups + let userGroups; for (const challenge of challenges) { - challenge.groups = _.filter(challenge.groups, g => !_.includes(['null', 'undefined'], _.toString(g).toLowerCase())) - if (!challenge.groups || _.get(challenge, 'groups.length', 0) === 0 || !needToCheckForGroupAccess) { - res.push(challenge) + challenge.groups = _.filter( + challenge.groups, + (g) => !_.includes(["null", "undefined"], _.toString(g).toLowerCase()) + ); + if ( + !challenge.groups || + _.get(challenge, "groups.length", 0) === 0 || + !needToCheckForGroupAccess + ) { + res.push(challenge); } else if (currentUser) { if (_.isNil(userGroups)) { - userGroups = await getCompleteUserGroupTreeIds(currentUser.userId) + userGroups = await getCompleteUserGroupTreeIds(currentUser.userId); } // get user groups if not yet if (_.find(challenge.groups, (group) => !!_.find(userGroups, (ug) => ug === group))) { - res.push(challenge) + res.push(challenge); } } } - return res + return res; } /** @@ -1066,10 +1075,12 @@ async function _filterChallengesByGroupsAccess (currentUser, challenges) { * @param {Object} currentUser the user who perform operation * @param {Object} challenge the challenge to check */ -async function ensureAccessibleByGroupsAccess (currentUser, challenge) { - const filtered = await _filterChallengesByGroupsAccess(currentUser, [challenge]) +async function ensureAccessibleByGroupsAccess(currentUser, challenge) { + const filtered = await _filterChallengesByGroupsAccess(currentUser, [challenge]); if (filtered.length === 0) { - throw new errors.ForbiddenError("helper ensureAcessibilityToModifiedGroups :: You don't have access to this group!") + throw new errors.ForbiddenError( + "helper ensureAcessibilityToModifiedGroups :: You don't have access to this group!" + ); } } @@ -1079,18 +1090,20 @@ async function ensureAccessibleByGroupsAccess (currentUser, challenge) { * @param {Object} currentUser the user who perform operation * @param {Object} challenge the challenge to check */ -async function _ensureAccessibleForTaskChallenge (currentUser, challenge) { - let memberResources +async function _ensureAccessibleForTaskChallenge(currentUser, challenge) { + let memberResources; // Check if challenge is task and apply security rules - if (_.get(challenge, 'task.isTask', false) && _.get(challenge, 'task.isAssigned', false)) { + if (_.get(challenge, "task.isTask", false) && _.get(challenge, "task.isAssigned", false)) { if (currentUser) { if (!currentUser.isMachine) { - memberResources = await listResourcesByMemberAndChallenge(currentUser.userId, challenge.id) + memberResources = await listResourcesByMemberAndChallenge(currentUser.userId, challenge.id); } } - const canAccesChallenge = _.isUndefined(currentUser) ? false : currentUser.isMachine || hasAdminRole(currentUser) || !_.isEmpty(memberResources) + const canAccesChallenge = _.isUndefined(currentUser) + ? false + : currentUser.isMachine || hasAdminRole(currentUser) || !_.isEmpty(memberResources); if (!canAccesChallenge) { - throw new errors.ForbiddenError(`You don't have access to view this challenge`) + throw new errors.ForbiddenError(`You don't have access to view this challenge`); } } } @@ -1101,11 +1114,11 @@ async function _ensureAccessibleForTaskChallenge (currentUser, challenge) { * @param {Object} currentUser the user who perform operation * @param {Object} challenge the challenge to check */ -async function ensureUserCanViewChallenge (currentUser, challenge) { +async function ensureUserCanViewChallenge(currentUser, challenge) { // check groups authorization - await ensureAccessibleByGroupsAccess(currentUser, challenge) + await ensureAccessibleByGroupsAccess(currentUser, challenge); // check if user can access a challenge that is a task - await _ensureAccessibleForTaskChallenge(currentUser, challenge) + await _ensureAccessibleForTaskChallenge(currentUser, challenge); } /** @@ -1113,52 +1126,59 @@ async function ensureUserCanViewChallenge (currentUser, challenge) { * * @param {Object} currentUser the user who perform operation * @param {Object} challenge the challenge to check - * @returns {undefined} + * @returns {Promise} */ -async function ensureUserCanModifyChallenge (currentUser, challenge) { +async function ensureUserCanModifyChallenge(currentUser, challenge) { // check groups authorization - await ensureAccessibleByGroupsAccess(currentUser, challenge) + await ensureAccessibleByGroupsAccess(currentUser, challenge); // check full access - const isUserHasFullAccess = await userHasFullAccess(challenge.id, currentUser.userId) - if (!currentUser.isMachine && !hasAdminRole(currentUser) && challenge.createdBy.toLowerCase() !== currentUser.handle.toLowerCase() && !isUserHasFullAccess) { - throw new errors.ForbiddenError(`Only M2M, admin, challenge's copilot or users with full access can perform modification.`) + const isUserHasFullAccess = await userHasFullAccess(challenge.id, currentUser.userId); + if ( + !currentUser.isMachine && + !hasAdminRole(currentUser) && + challenge.createdBy.toLowerCase() !== currentUser.handle.toLowerCase() && + !isUserHasFullAccess + ) { + throw new errors.ForbiddenError( + `Only M2M, admin, challenge's copilot or users with full access can perform modification.` + ); } } /** - * Calculate the sum of prizes. - * - * @param {Array} prizes the list of prize - * @returns {Number} the result prize - */ -function sumOfPrizes (prizes) { - let sum = 0 + * Calculate the sum of prizes. + * + * @param {Array} prizes the list of prize + * @returns {Number} the result prize + */ +function sumOfPrizes(prizes) { + let sum = 0; if (!prizes.length) { - return sum + return sum; } for (const prize of prizes) { - sum += prize.value + sum += prize.value; } - return sum + return sum; } /** - * Get group by id - * @param {String} groupId the group id - * @returns {Promise} the group - */ -async function getGroupById (groupId) { - const token = await getM2MToken() + * Get group by id + * @param {String} groupId the group id + * @returns {Promise} the group + */ +async function getGroupById(groupId) { + const token = await m2mHelper.getM2MToken(); try { const result = await axios.get(`${config.GROUPS_API_URL}/${groupId}`, { - headers: { Authorization: `Bearer ${token}` } - }) - return result.data + headers: { Authorization: `Bearer ${token}` }, + }); + return result.data; } catch (err) { if (err.response.status === HttpStatus.NOT_FOUND) { - return + return; } - throw err + throw err; } } @@ -1167,30 +1187,30 @@ async function getGroupById (groupId) { * @param {String} challengeId the challenge id * @returns {Array} the submission */ -async function getChallengeSubmissions (challengeId) { - const token = await getM2MToken() - let allSubmissions = [] +async function getChallengeSubmissions(challengeId) { + const token = await m2mHelper.getM2MToken(); + let allSubmissions = []; // get search is paginated, we need to get all pages' data - let page = 1 + let page = 1; while (true) { const result = await axios.get(`${config.SUBMISSIONS_API_URL}?challengeId=${challengeId}`, { headers: { Authorization: `Bearer ${token}` }, params: { page, - perPage: 100 - } - }) - const ids = result.data || [] + perPage: 100, + }, + }); + const ids = result.data || []; if (ids.length === 0) { - break + break; } - allSubmissions = allSubmissions.concat(ids) - page += 1 - if (result.headers['x-total-pages'] && page > Number(result.headers['x-total-pages'])) { - break + allSubmissions = allSubmissions.concat(ids); + page += 1; + if (result.headers["x-total-pages"] && page > Number(result.headers["x-total-pages"])) { + break; } } - return allSubmissions + return allSubmissions; } /** @@ -1198,13 +1218,13 @@ async function getChallengeSubmissions (challengeId) { * @param {String} userId the user ID * @returns {Object} */ -async function getMemberById (userId) { - const token = await getM2MToken() +async function getMemberById(userId) { + const token = await m2mHelper.getM2MToken(); const res = await axios.get(`${config.MEMBERS_API_URL}?userId=${userId}`, { - headers: { Authorization: `Bearer ${token}` } - }) - if (res.data.length > 0) return res.data[0] - return {} + headers: { Authorization: `Bearer ${token}` }, + }); + if (res.data.length > 0) return res.data[0]; + return {}; } /** @@ -1212,12 +1232,12 @@ async function getMemberById (userId) { * @param {String} handle the user handle * @returns {Object} */ -async function getMemberByHandle (handle) { - const token = await getM2MToken() +async function getMemberByHandle(handle) { + const token = await m2mHelper.getM2MToken(); const res = await axios.get(`${config.MEMBERS_API_URL}/${handle}`, { - headers: { Authorization: `Bearer ${token}` } - }) - return res.data || {} + headers: { Authorization: `Bearer ${token}` }, + }); + return res.data || {}; } /** @@ -1226,12 +1246,12 @@ async function getMemberByHandle (handle) { * @param {Array} recipients the array of recipients in { userId || email || handle } format * @param {Object} data the data */ -async function sendSelfServiceNotification (type, recipients, data) { +async function sendSelfServiceNotification(type, recipients, data) { try { await postBusEvent(constants.Topics.Notifications, { notifications: [ { - serviceId: 'email', + serviceId: "email", type, details: { from: config.EMAIL_FROM, @@ -1239,16 +1259,16 @@ async function sendSelfServiceNotification (type, recipients, data) { cc: [...constants.SelfServiceNotificationSettings[type].cc], data: { ...data, - supportUrl: `${config.SELF_SERVICE_APP_URL}/support` + supportUrl: `${config.SELF_SERVICE_APP_URL}/support`, }, sendgridTemplateId: constants.SelfServiceNotificationSettings[type].sendgridTemplateId, - version: 'v3' - } - } - ] - }) + version: "v3", + }, + }, + ], + }); } catch (e) { - logger.debug(`Failed to post notification ${type}: ${e.message}`) + logger.debug(`Failed to post notification ${type}: ${e.message}`); } } @@ -1256,31 +1276,45 @@ async function sendSelfServiceNotification (type, recipients, data) { * Submit a request to zendesk * @param {Object} request the request */ -async function submitZendeskRequest (request) { +async function submitZendeskRequest(request) { try { - const res = await axios.post(`${config.ZENDESK_API_URL}/api/v2/requests`, { - request: { - ...request - } - }, { - auth: { - username: `${request.requester.email}/token`, - password: config.ZENDESK_API_TOKEN + const res = await axios.post( + `${config.ZENDESK_API_URL}/api/v2/requests`, + { + request: { + ...request, + }, + }, + { + auth: { + username: `${request.requester.email}/token`, + password: config.ZENDESK_API_TOKEN, + }, } - }) - return res.data || {} + ); + return res.data || {}; } catch (e) { - logger.debug(`Failed to submit request: ${e.message}`) - throw e + logger.debug(`Failed to submit request: ${e.message}`); + throw e; } } -function getFromInternalCache (key) { - return internalCache.get(key) +function getFromInternalCache(key) { + return internalCache.get(key); +} + +function setToInternalCache(key, value) { + internalCache.set(key, value); +} + +function flushInternalCache() { + internalCache.flushAll(); } -function setToInternalCache (key, value) { - internalCache.set(key, value) +function grpcErrorToHTTPCode(grpcErrorCode) { + if (grpcErrorCode == 2) return HttpStatus.NOT_FOUND; + + return HttpStatus.INTERNAL_SERVER_ERROR; } module.exports = { @@ -1288,7 +1322,6 @@ module.exports = { autoWrapExpress, setResHeaders, checkIfExists, - hasAdminRole, toString, getById, getByIds, @@ -1307,14 +1340,12 @@ module.exports = { ensureNoDuplicateOrNullElements, postBusEvent, getESClient, - ensureProjectExist, calculateChallengeEndDate, listChallengesByMember, listResourcesByMemberAndChallenge, validateESRefreshMethod, getProjectDefaultTerms, validateChallengeTerms, - getProjectBillingInformation, expandWithSubGroups, getCompleteUserGroupTreeIds, expandWithParentGroups, @@ -1339,5 +1370,9 @@ module.exports = { submitZendeskRequest, updateSelfServiceProjectInfo, getFromInternalCache, - setToInternalCache -} + setToInternalCache, + grpcErrorToHTTPCode, + flushInternalCache, +}; + +logger.buildService(module.exports); diff --git a/src/common/logger.js b/src/common/logger.js index 8217199f..82ae38ed 100644 --- a/src/common/logger.js +++ b/src/common/logger.js @@ -2,24 +2,21 @@ * This module contains the winston logger configuration. */ -const _ = require('lodash') -const Joi = require('joi') -const util = require('util') -const config = require('config') -const getParams = require('get-parameter-names') -const { createLogger, format, transports } = require('winston') +const _ = require("lodash"); +const Joi = require("joi"); +const util = require("util"); +const config = require("config"); +const getParams = require("get-parameter-names"); +const { createLogger, format, transports } = require("winston"); const logger = createLogger({ level: config.LOG_LEVEL, transports: [ new transports.Console({ - format: format.combine( - format.colorize(), - format.simple() - ) - }) - ] -}) + format: format.combine(format.colorize(), format.simple()), + }), + ], +}); /** * Log error details with signature @@ -28,17 +25,17 @@ const logger = createLogger({ */ logger.logFullError = (err, signature) => { if (!err) { - return + return; } if (signature) { - logger.error(`Error happened in ${signature}`) + logger.error(`Error happened in ${signature}`); } - logger.error(util.inspect(err)) + logger.error(util.inspect(err)); if (!err.logged) { - logger.error(err.stack) - err.logged = true + logger.error(err.stack); + err.logged = true; } -} +}; /** * Remove invalid properties from the object and hide long arrays @@ -48,22 +45,24 @@ logger.logFullError = (err, signature) => { */ const _sanitizeObject = (obj) => { try { - return JSON.parse(JSON.stringify(obj, (name, value) => { - // Array of field names that should not be logged - // add field if necessary (password, tokens etc) - const removeFields = ['userToken'] - if (_.includes(removeFields, name)) { - return '' - } - if (_.isArray(value) && value.length > 30) { - return `Array(${value.length})` - } - return value - })) + return JSON.parse( + JSON.stringify(obj, (name, value) => { + // Array of field names that should not be logged + // add field if necessary (password, tokens etc) + const removeFields = ["userToken"]; + if (_.includes(removeFields, name)) { + return ""; + } + if (_.isArray(value) && value.length > 30) { + return `Array(${value.length})`; + } + return value; + }) + ); } catch (e) { - return obj + return obj; } -} +}; /** * Convert array with arguments to object @@ -72,43 +71,43 @@ const _sanitizeObject = (obj) => { * @private */ const _combineObject = (params, arr) => { - const ret = {} + const ret = {}; _.each(arr, (arg, i) => { - ret[params[i]] = arg - }) - return ret -} + ret[params[i]] = arg; + }); + return ret; +}; /** * Decorate all functions of a service and log debug information if DEBUG is enabled * @param {Object} service the service */ logger.decorateWithLogging = (service) => { - if (config.LOG_LEVEL !== 'debug') { - return + if (config.LOG_LEVEL !== "debug") { + return; } _.each(service, (method, name) => { - const params = method.params || getParams(method) + const params = method.params || getParams(method); service[name] = async function () { // logger.debug(`ENTER ${name}`) // logger.debug('input arguments') - const args = Array.prototype.slice.call(arguments) - logger.debug(util.inspect(_sanitizeObject(_combineObject(params, args)))) + const args = Array.prototype.slice.call(arguments); + logger.debug(util.inspect(_sanitizeObject(_combineObject(params, args)))); try { - const result = await method.apply(this, arguments) + const result = await method.apply(this, arguments); // logger.debug(`EXIT ${name}`) // logger.debug('output arguments') if (result !== null && result !== undefined) { - logger.debug(util.inspect(_sanitizeObject(result))) + logger.debug(util.inspect(_sanitizeObject(result))); } - return result + return result; } catch (e) { - logger.logFullError(e, name) - throw e + logger.logFullError(e, name); + throw e; } - } - }) -} + }; + }); +}; /** * Decorate all functions of a service and validate input values @@ -119,34 +118,34 @@ logger.decorateWithLogging = (service) => { logger.decorateWithValidators = function (service) { _.each(service, (method, name) => { if (!method.schema) { - return + return; } - const params = getParams(method) + const params = getParams(method); service[name] = async function () { - const args = Array.prototype.slice.call(arguments) - const value = _combineObject(params, args) - const normalized = Joi.attempt(value, method.schema) + const args = Array.prototype.slice.call(arguments); + const value = _combineObject(params, args); + const normalized = Joi.attempt(value, method.schema); - const newArgs = [] + const newArgs = []; // Joi will normalize values // for example string number '1' to 1 // if schema type is number _.each(params, (param) => { - newArgs.push(normalized[param]) - }) - return method.apply(this, newArgs) - } - service[name].params = params - }) -} + newArgs.push(normalized[param]); + }); + return method.apply(this, newArgs); + }; + service[name].params = params; + }); +}; /** * Apply logger and validation decorators * @param {Object} service the service to wrap */ logger.buildService = (service) => { - logger.decorateWithValidators(service) + logger.decorateWithValidators(service); // logger.decorateWithLogging(service) -} +}; -module.exports = logger +module.exports = logger; diff --git a/src/common/m2m-helper.js b/src/common/m2m-helper.js new file mode 100644 index 00000000..62c51678 --- /dev/null +++ b/src/common/m2m-helper.js @@ -0,0 +1,20 @@ +const _ = require("lodash"); +const config = require("config"); +const m2mAuth = require("tc-core-library-js").auth.m2m; + +class M2MHelper { + static m2m = null; + + constructor() { + M2MHelper.m2m = m2mAuth(_.pick(config, ["AUTH0_URL", "AUTH0_AUDIENCE", "TOKEN_CACHE_TIME"])); + } + /** + * Get M2M token. + * @returns {Promise} the M2M token + */ + getM2MToken() { + return M2MHelper.m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET); + } +} + +module.exports = new M2MHelper(); diff --git a/src/common/phase-helper.js b/src/common/phase-helper.js index 3b3278ef..1ffb99a7 100644 --- a/src/common/phase-helper.js +++ b/src/common/phase-helper.js @@ -1,9 +1,22 @@ -const _ = require('lodash') -const uuid = require('uuid/v4') -const moment = require('moment') +const { GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT } = process.env; -const errors = require('./errors') -const helper = require('./helper') +const { + DomainHelper: { getLookupCriteria, getScanCriteria }, +} = require("@topcoder-framework/lib-common"); + +const { PhaseDomain, TimelineTemplateDomain } = require("@topcoder-framework/domain-challenge"); + +const _ = require("lodash"); + +const uuid = require("uuid/v4"); +const moment = require("moment"); + +const errors = require("./errors"); + +const phaseService = require("../services/PhaseService"); +const timelineTemplateService = require("../services/TimelineTemplateService"); + +const phaseDomain = new PhaseDomain(GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT); class ChallengePhaseHelper { /** @@ -12,168 +25,308 @@ class ChallengePhaseHelper { * @param {Date} startDate the challenge start date * @param {String} timelineTemplateId the timeline template id */ - async populatePhases (phases, startDate, timelineTemplateId) { + async populatePhases(phases, startDate, timelineTemplateId) { if (_.isUndefined(timelineTemplateId)) { - throw new errors.BadRequestError(`Invalid timeline template ID: ${timelineTemplateId}`) + throw new errors.BadRequestError(`Invalid timeline template ID: ${timelineTemplateId}`); } - const { timelineTempate, timelineTemplateMap } = await this.getTemplateAndTemplateMap(timelineTemplateId) - const { phaseDefinitionMap } = await this.getPhaseDefinitionsAndMap() + const { timelineTempate, timelineTemplateMap } = await this.getTemplateAndTemplateMap( + timelineTemplateId + ); + const { phaseDefinitionMap } = await this.getPhaseDefinitionsAndMap(); if (!phases || phases.length === 0) { // auto populate phases for (const p of timelineTempate) { - phases.push({ ...p }) + phases.push({ ...p }); } } for (const p of phases) { - const phaseDefinition = phaseDefinitionMap.get(p.phaseId) + const phaseDefinition = phaseDefinitionMap.get(p.phaseId); - p.id = uuid() - p.name = phaseDefinition.name - p.description = phaseDefinition.description + // TODO: move to domain-challenge + p.id = uuid(); + p.name = phaseDefinition.name; + p.description = phaseDefinition.description; // set p.open based on current phase - const phaseTemplate = timelineTemplateMap.get(p.phaseId) + const phaseTemplate = timelineTemplateMap.get(p.phaseId); if (phaseTemplate) { if (!p.duration) { - p.duration = phaseTemplate.defaultDuration + p.duration = phaseTemplate.defaultDuration; } if (phaseTemplate.predecessor) { - const predecessor = _.find(phases, { phaseId: phaseTemplate.predecessor }) + const predecessor = _.find(phases, { + phaseId: phaseTemplate.predecessor, + }); if (!predecessor) { - throw new errors.BadRequestError(`Predecessor ${phaseTemplate.predecessor} not found in given phases.`) + throw new errors.BadRequestError( + `Predecessor ${phaseTemplate.predecessor} not found in given phases.` + ); } - p.predecessor = phaseTemplate.predecessor + p.predecessor = phaseTemplate.predecessor; + console.log("Setting predecessor", p.predecessor, "for phase", p.phaseId); } } } // calculate dates if (!startDate) { - return + return; } // sort phases by predecessor phases.sort((a, b) => { if (a.predecessor === b.phaseId) { - return 1 + return 1; } if (b.predecessor === a.phaseId) { - return -1 + return -1; } - return 0 - }) + return 0; + }); - let isSubmissionPhaseOpen = false + let isSubmissionPhaseOpen = false; for (let p of phases) { - const predecessor = timelineTemplateMap.get(p.predecessor) + const predecessor = timelineTemplateMap.get(p.predecessor); if (predecessor == null) { - if (p.name === 'Registration') { - p.scheduledStartDate = moment(startDate).toDate() + if (p.name === "Registration") { + p.scheduledStartDate = moment(startDate).toDate(); } - if (_.includes(['Submission', 'Checkpoint Submission'], p.name)) { - if (p.scheduledStartDate != null) { - p.scheduledStartDate = moment(p.scheduledStartDate).toDate() - } else { - p.scheduledStartDate = moment(startDate).add(5, 'minutes').toDate() - } + if (p.name === "Submission") { + p.scheduledStartDate = moment(startDate).add(5, "minutes").toDate(); } if (moment(p.scheduledStartDate).isSameOrBefore(moment())) { - p.actualStartDate = p.scheduledStartDate + p.actualStartDate = p.scheduledStartDate; } else { - delete p.actualStartDate + delete p.actualStartDate; } - p.scheduledEndDate = moment(p.scheduledStartDate).add(p.duration, 'seconds').toDate() + p.scheduledEndDate = moment(p.scheduledStartDate).add(p.duration, "seconds").toDate(); if (moment(p.scheduledEndDate).isBefore(moment())) { - delete p.actualEndDate + delete p.actualEndDate; } else { - p.actualEndDate = p.scheduledEndDate + p.actualEndDate = p.scheduledEndDate; } } else { - const precedecessorPhase = _.find(phases, { phaseId: predecessor.phaseId }) + const precedecessorPhase = _.find(phases, { + phaseId: predecessor.phaseId, + }); if (precedecessorPhase == null) { - throw new errors.BadRequestError(`Predecessor ${predecessor.phaseId} not found in given phases.`) + throw new errors.BadRequestError( + `Predecessor ${predecessor.phaseId} not found in given phases.` + ); } - let phaseEndDate = moment(precedecessorPhase.scheduledEndDate) - if (precedecessorPhase.actualEndDate != null && moment(precedecessorPhase.actualEndDate).isAfter(phaseEndDate)) { - phaseEndDate = moment(precedecessorPhase.actualEndDate) + let phaseEndDate = moment(precedecessorPhase.scheduledEndDate); + if ( + precedecessorPhase.actualEndDate != null && + moment(precedecessorPhase.actualEndDate).isAfter(phaseEndDate) + ) { + phaseEndDate = moment(precedecessorPhase.actualEndDate); } else { - phaseEndDate = moment(precedecessorPhase.scheduledEndDate) + phaseEndDate = moment(precedecessorPhase.scheduledEndDate); } - p.scheduledStartDate = phaseEndDate.toDate() - p.scheduledEndDate = moment(p.scheduledStartDate).add(p.duration, 'seconds').toDate() + p.scheduledStartDate = phaseEndDate.toDate(); + p.scheduledEndDate = moment(p.scheduledStartDate).add(p.duration, "seconds").toDate(); } - - p.isOpen = moment().isBetween(p.scheduledStartDate, p.scheduledEndDate) - + p.isOpen = moment().isBetween(p.scheduledStartDate, p.scheduledEndDate); if (p.isOpen) { - if (p.name === 'Submission') { - isSubmissionPhaseOpen = true + if (p.name === "Submission") { + isSubmissionPhaseOpen = true; } - delete p.actualEndDate + delete p.actualEndDate; } if (moment(p.scheduledStartDate).isAfter(moment())) { - delete p.actualStartDate - delete p.actualEndDate + delete p.actualStartDate; + delete p.actualEndDate; } - if (p.name === 'Post-Mortem' && isSubmissionPhaseOpen) { - delete p.actualStartDate - delete p.actualEndDate - p.isOpen = false + if (p.name === "Post-Mortem" && isSubmissionPhaseOpen) { + delete p.actualStartDate; + delete p.actualEndDate; + p.isOpen = false; + } + + if (p.constraints == null) { + p.constraints = []; + } + } + } + + async populatePhasesForChallengeCreation(phases, startDate, timelineTemplateId) { + if (_.isUndefined(timelineTemplateId)) { + throw new errors.BadRequestError(`Invalid timeline template ID: ${timelineTemplateId}`); + } + const { timelineTempate } = await this.getTemplateAndTemplateMap(timelineTemplateId); + const { phaseDefinitionMap } = await this.getPhaseDefinitionsAndMap(); + const finalPhases = _.map(timelineTempate, (phaseFromTemplate) => { + const phaseDefinition = phaseDefinitionMap.get(phaseFromTemplate.phaseId); + const phaseFromInput = _.find(phases, (p) => p.phaseId === phaseFromTemplate.phaseId); + const phase = { + id: uuid(), + phaseId: phaseFromTemplate.phaseId, + name: phaseDefinition.name, + description: phaseDefinition.description, + duration: _.defaultTo(_.get(phaseFromInput, "duration"), phaseFromTemplate.defaultDuration), + isOpen: false, + predecessor: phaseFromTemplate.predecessor, + constraints: _.defaultTo(_.get(phaseFromInput, "constraints"), []), + scheduledStartDate: undefined, + scheduledEndDate: undefined, + actualStartDate: undefined, + actualEndDate: undefined, + }; + if (_.isUndefined(phase.predecessor)) { + if (_.isUndefined(_.get(phaseFromInput, "scheduledStartDate"))) { + phase.scheduledStartDate = moment(startDate).toDate().toISOString(); + } else { + phase.scheduledStartDate = moment(_.get(phaseFromInput, "scheduledStartDate")).toDate().toISOString(); + } + phase.scheduledEndDate = moment(phase.scheduledStartDate) + .add(phase.duration, "seconds") + .toDate().toISOString(); + } + return phase; + }); + for (let phase of finalPhases) { + if (_.isUndefined(phase.predecessor)) { + continue; } + const precedecessorPhase = _.find(finalPhases, { + phaseId: phase.predecessor, + }); + if (phase.name === "Iterative Review Phase") { + phase.scheduledStartDate = precedecessorPhase.scheduledStartDate; + } else { + phase.scheduledStartDate = precedecessorPhase.scheduledEndDate; + } + phase.scheduledEndDate = moment(phase.scheduledStartDate) + .add(phase.duration, "seconds") + .toDate().toISOString(); } + return finalPhases; + } - // phases.sort((a, b) => moment(a.scheduledStartDate).isAfter(b.scheduledStartDate)) + async populatePhasesForChallengeUpdate( + challengePhases, + newPhases, + timelineTemplateId, + isBeingActivated + ) { + const { timelineTempate, timelineTemplateMap } = await this.getTemplateAndTemplateMap( + timelineTemplateId + ); + const { phaseDefinitionMap } = await this.getPhaseDefinitionsAndMap(); + + const updatedPhases = _.map(challengePhases, (phase) => { + const phaseFromTemplate = timelineTemplateMap.get(phase.phaseId); + const phaseDefinition = phaseDefinitionMap.get(phase.phaseId); + const updatedPhase = { + ...phase, + predecessor: phaseFromTemplate.predecessor, + description: phaseDefinition.description, + }; + if (!_.isUndefined(phase.actualEndDate)) { + return updatedPhase; + } + if (updatedPhase.name === "Iterative Review Phase") { + return updatedPhase; + } + const newPhase = _.find(newPhases, (p) => p.phaseId === updatedPhase.phaseId); + if (_.isUndefined(newPhase) && !isBeingActivated) { + return updatedPhase; + } + updatedPhase.duration = _.defaultTo(_.get(newPhase, "duration"), updatedPhase.duration); + if (_.isUndefined(updatedPhase.predecessor)) { + if ( + isBeingActivated && + moment( + _.defaultTo(_.get(newPhase, "scheduledStartDate"), updatedPhase.scheduledStartDate) + ).isSameOrBefore(moment()) + ) { + updatedPhase.isOpen = true; + updatedPhase.scheduledStartDate = moment().toDate().toISOString(); + updatedPhase.actualStartDate = updatedPhase.scheduledStartDate; + } else if ( + updatedPhase.isOpen === false && + !_.isUndefined(_.get(newPhase, "scheduledStartDate")) + ) { + updatedPhase.scheduledStartDate = moment(newPhase.scheduledStartDate).toDate().toISOString(); + } + updatedPhase.scheduledEndDate = moment(updatedPhase.scheduledStartDate) + .add(updatedPhase.duration, "seconds") + .toDate().toISOString(); + } + if (!_.isUndefined(newPhase) && !_.isUndefined(newPhase.constraints)) { + updatedPhase.constraints = newPhase.constraints; + } + return updatedPhase; + }); + for (let phase of updatedPhases) { + if (_.isUndefined(phase.predecessor)) { + continue; + } + if (phase.name === "Iterative Review Phase") { + continue; + } + const precedecessorPhase = _.find(updatedPhases, { + phaseId: phase.predecessor, + }); + phase.scheduledStartDate = precedecessorPhase.scheduledEndDate; + phase.scheduledEndDate = moment(phase.scheduledStartDate) + .add(phase.duration, "seconds") + .toDate().toISOString(); + } + return updatedPhases; } - async validatePhases (phases) { + async validatePhases(phases) { if (!phases || phases.length === 0) { - return + return; } - const records = await helper.scan('Phase') - const map = new Map() + const { items: records } = await phaseDomain.scan({ criteria: getScanCriteria({}) }); + const map = new Map(); _.each(records, (r) => { - map.set(r.id, r) - }) - const invalidPhases = _.filter(phases, (p) => !map.has(p.phaseId)) + map.set(r.id, r); + }); + const invalidPhases = _.filter(phases, (p) => !map.has(p.phaseId)); if (invalidPhases.length > 0) { throw new errors.BadRequestError( `The following phases are invalid: ${toString(invalidPhases)}` - ) + ); } } - async getPhaseDefinitionsAndMap () { - const records = await helper.scan('Phase') - const map = new Map() + async getPhaseDefinitionsAndMap() { + const { result: records } = await phaseService.searchPhases(); + + const map = new Map(); _.each(records, (r) => { - map.set(r.id, r) - }) - return { phaseDefinitions: records, phaseDefinitionMap: map } + map.set(r.id, r); + }); + return { phaseDefinitions: records, phaseDefinitionMap: map }; } - async getTemplateAndTemplateMap (timelineTemplateId) { - const records = await helper.getById('TimelineTemplate', timelineTemplateId) - const map = new Map() + async getTemplateAndTemplateMap(timelineTemplateId) { + const records = await timelineTemplateService.getTimelineTemplate(timelineTemplateId); + + const map = new Map(); _.each(records.phases, (r) => { - map.set(r.phaseId, r) - }) + map.set(r.phaseId, r); + }); return { timelineTempate: records.phases, - timelineTemplateMap: map - } + timelineTemplateMap: map, + }; } } -module.exports = new ChallengePhaseHelper() +module.exports = new ChallengePhaseHelper(); diff --git a/src/common/project-helper.js b/src/common/project-helper.js new file mode 100644 index 00000000..e344267d --- /dev/null +++ b/src/common/project-helper.js @@ -0,0 +1,94 @@ +const _ = require("lodash"); + +const axios = require("axios"); +const config = require("config"); +const HttpStatus = require("http-status-codes"); +const m2mHelper = require("./m2m-helper"); +const { hasAdminRole } = require("./role-helper"); +const errors = require("./errors"); + +class ProjectHelper { + /** + * Get Project Details + * @param {String} projectId the project id + * @param {String} currentUser the user + * + * @returns {Promise} the project details + */ + async getProject(projectId, currentUser) { + let token = await m2mHelper.getM2MToken(); + const url = `${config.PROJECTS_API_URL}/${projectId}`; + try { + const res = await axios.get(url, { + headers: { Authorization: `Bearer ${token}` }, + }); + if (currentUser.isMachine || hasAdminRole(currentUser)) { + return res.data; + } + if ( + _.get(res, "data.type") === "self-service" && + _.includes(config.SELF_SERVICE_WHITELIST_HANDLES, currentUser.handle.toLowerCase()) + ) { + return res.data; + } + if ( + !_.find( + _.get(res, "data.members", []), + (m) => _.toString(m.userId) === _.toString(currentUser.userId) + ) + ) { + throw new errors.ForbiddenError(`You don't have access to project with ID: ${projectId}`); + } + return res.data; + } catch (err) { + if (_.get(err, "response.status") === HttpStatus.NOT_FOUND) { + throw new errors.BadRequestError(`Project with id: ${projectId} doesn't exist`); + } else { + // re-throw other error + throw err; + } + } + } + + /** + * This functions gets the default billing account for a given project id + * + * @param {Number} projectId The id of the project for which to get the default terms of use + * @returns {Promise} The billing account ID + */ + async getProjectBillingInformation(projectId) { + const token = await m2mHelper.getM2MToken(); + const projectUrl = `${config.PROJECTS_API_URL}/${projectId}/billingAccount`; + try { + const res = await axios.get(projectUrl, { + headers: { Authorization: `Bearer ${token}` }, + }); + + let markup = _.get(res, "data.markup", null) + ? _.toNumber(_.get(res, "data.markup", null)) + : null; + + if (markup && markup > 0) { + // Change int returned from api to decimal + markup = markup / 100; + } + return { + billingAccountId: _.get(res, "data.tcBillingAccountId", null), + markup, + }; + } catch (err) { + const responseCode = _.get(err, "response.status"); + + if (responseCode === HttpStatus.NOT_FOUND) { + return { + billingAccountId: null, + markup: null, + }; + } else { + throw err; + } + } + } +} + +module.exports = new ProjectHelper(); diff --git a/src/common/role-helper.js b/src/common/role-helper.js new file mode 100644 index 00000000..f30720f9 --- /dev/null +++ b/src/common/role-helper.js @@ -0,0 +1,20 @@ +const constants = require("../../app-constants"); + +/** + * Check if the user has admin role + * @param {Object} authUser the user + */ +function hasAdminRole(authUser) { + if (authUser && authUser.roles) { + for (const role of authUser.roles) { + if (role.toLowerCase() === constants.UserRoles.Admin.toLowerCase()) { + return true; + } + } + } + return false; +} + +module.exports = { + hasAdminRole, +}; diff --git a/src/common/s3ParseUrl.js b/src/common/s3ParseUrl.js index 242ced07..374dd887 100644 --- a/src/common/s3ParseUrl.js +++ b/src/common/s3ParseUrl.js @@ -2,48 +2,52 @@ * Extract components from s3 url. */ -module.exports = function s3ParseUrl (url) { - var decodedUrl = decodeURIComponent(url) - let match +module.exports = function s3ParseUrl(url) { + var decodedUrl = decodeURIComponent(url); + let match; // http://s3.amazonaws.com/bucket/key1/key2 - match = decodedUrl.match(/^https?:\/\/s3.amazonaws.com\/([^/]+)\/?(.*?)$/) + match = decodedUrl.match(/^https?:\/\/s3.amazonaws.com\/([^/]+)\/?(.*?)$/); if (match) { return { bucket: match[1], key: match[2], - region: '' - } + region: "", + }; } // http://s3-aws-region.amazonaws.com/bucket/key1/key2 - match = decodedUrl.match(/^https?:\/\/s3-([^.]+).amazonaws.com\/([^/]+)\/?(.*?)$/) + match = decodedUrl.match( + /^https?:\/\/s3-([^.]+).amazonaws.com\/([^/]+)\/?(.*?)$/ + ); if (match) { return { bucket: match[2], key: match[3], - region: match[1] - } + region: match[1], + }; } // http://bucket.s3.amazonaws.com/key1/key2 - match = decodedUrl.match(/^https?:\/\/([^.]+).s3.amazonaws.com\/?(.*?)$/) + match = decodedUrl.match(/^https?:\/\/([^.]+).s3.amazonaws.com\/?(.*?)$/); if (match) { return { bucket: match[1], key: match[2], - region: '' - } + region: "", + }; } // http://bucket.s3-aws-region.amazonaws.com/key1/key2 or, // http://bucket.s3.aws-region.amazonaws.com/key1/key2 - match = decodedUrl.match(/^https?:\/\/([^.]+).(?:s3-|s3\.)([^.]+).amazonaws.com\/?(.*?)$/) + match = decodedUrl.match( + /^https?:\/\/([^.]+).(?:s3-|s3\.)([^.]+).amazonaws.com\/?(.*?)$/ + ); if (match) { return { bucket: match[1], key: match[3], - region: match[2] - } + region: match[2], + }; } -} +}; diff --git a/src/controllers/AttachmentController.js b/src/controllers/AttachmentController.js index a1f64963..93c0d469 100644 --- a/src/controllers/AttachmentController.js +++ b/src/controllers/AttachmentController.js @@ -1,19 +1,23 @@ /** * Controller for attachment endpoints */ -const HttpStatus = require('http-status-codes') -const _ = require('lodash') -const service = require('../services/AttachmentService') +const HttpStatus = require("http-status-codes"); +const _ = require("lodash"); +const service = require("../services/AttachmentService"); /** * Create attachment * @param {Object} req the request * @param {Object} res the response */ -async function createAttachment (req, res) { - const body = _.isArray(req.body) ? req.body : [req.body] - const result = await service.createAttachment(req.authUser, req.params.challengeId, body) - res.status(HttpStatus.CREATED).send(result) +async function createAttachment(req, res) { + const body = _.isArray(req.body) ? req.body : [req.body]; + const result = await service.createAttachment( + req.authUser, + req.params.challengeId, + body + ); + res.status(HttpStatus.CREATED).send(result); } /** @@ -21,9 +25,13 @@ async function createAttachment (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function getAttachment (req, res) { - const result = await service.getAttachment(req.authUser, req.params.challengeId, req.params.attachmentId) - res.send(result) +async function getAttachment(req, res) { + const result = await service.getAttachment( + req.authUser, + req.params.challengeId, + req.params.attachmentId + ); + res.send(result); } /** @@ -31,9 +39,14 @@ async function getAttachment (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function updateAttachment (req, res) { - const result = await service.fullyUpdateAttachment(req.authUser, req.params.challengeId, req.params.attachmentId, req.body) - res.send(result) +async function updateAttachment(req, res) { + const result = await service.fullyUpdateAttachment( + req.authUser, + req.params.challengeId, + req.params.attachmentId, + req.body + ); + res.send(result); } /** @@ -41,9 +54,14 @@ async function updateAttachment (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function partiallyUpdateAttachment (req, res) { - const result = await service.partiallyUpdateAttachment(req.authUser, req.params.challengeId, req.params.attachmentId, req.body) - res.send(result) +async function partiallyUpdateAttachment(req, res) { + const result = await service.partiallyUpdateAttachment( + req.authUser, + req.params.challengeId, + req.params.attachmentId, + req.body + ); + res.send(result); } /** @@ -51,9 +69,13 @@ async function partiallyUpdateAttachment (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function deleteAttachment (req, res) { - const result = await service.deleteAttachment(req.authUser, req.params.challengeId, req.params.attachmentId) - res.send(result) +async function deleteAttachment(req, res) { + const result = await service.deleteAttachment( + req.authUser, + req.params.challengeId, + req.params.attachmentId + ); + res.send(result); } /** @@ -61,11 +83,15 @@ async function deleteAttachment (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function downloadAttachment (req, res) { - const result = await service.downloadAttachment(req.authUser, req.params.challengeId, req.params.attachmentId) - res.attachment(result.fileName) - res.set('Content-Type', result.mimetype) - res.send(result.data) +async function downloadAttachment(req, res) { + const result = await service.downloadAttachment( + req.authUser, + req.params.challengeId, + req.params.attachmentId + ); + res.attachment(result.fileName); + res.set("Content-Type", result.mimetype); + res.send(result.data); } module.exports = { @@ -74,5 +100,5 @@ module.exports = { updateAttachment, partiallyUpdateAttachment, deleteAttachment, - downloadAttachment -} + downloadAttachment, +}; diff --git a/src/controllers/AuditLogController.js b/src/controllers/AuditLogController.js index d4199aaa..771ec371 100644 --- a/src/controllers/AuditLogController.js +++ b/src/controllers/AuditLogController.js @@ -1,20 +1,20 @@ /** * Controller for challenge type endpoints */ -const service = require('../services/AuditLogService') -const helper = require('../common/helper') +const service = require("../services/AuditLogService"); +const helper = require("../common/helper"); /** * Search audit logs * @param {Object} req the request * @param {Object} res the response */ -async function searchAuditLogs (req, res) { - const result = await service.searchAuditLogs(req.query) - helper.setResHeaders(req, res, result) - res.send(result.result) +async function searchAuditLogs(req, res) { + const result = await service.searchAuditLogs(req.query); + helper.setResHeaders(req, res, result); + res.send(result.result); } module.exports = { - searchAuditLogs -} + searchAuditLogs, +}; diff --git a/src/controllers/ChallengeController.js b/src/controllers/ChallengeController.js index 3fe6ee5f..a956743e 100644 --- a/src/controllers/ChallengeController.js +++ b/src/controllers/ChallengeController.js @@ -1,37 +1,44 @@ /** * Controller for challenge endpoints */ -const HttpStatus = require('http-status-codes') -const service = require('../services/ChallengeService') -const helper = require('../common/helper') -const logger = require('../common/logger') +const HttpStatus = require("http-status-codes"); +const service = require("../services/ChallengeService"); +const helper = require("../common/helper"); +const logger = require("../common/logger"); /** * Search challenges * @param {Object} req the request * @param {Object} res the response */ -async function searchChallenges (req, res) { - let result = await service.searchChallenges(req.authUser, { ...req.query, ...req.body }) +async function searchChallenges(req, res) { + let result = await service.searchChallenges(req.authUser, { + ...req.query, + ...req.body, + }); if (!result.total && req.query.legacyId) { // maybe the legacyId is roundId for mm challenge // mm challenge use projectId as legacyId try { - logger.debug(`Staring to get mm challengeId`) - const legacyId = await helper.getProjectIdByRoundId(req.query.legacyId) - logger.debug(`Get mm challengeId successfully ${legacyId}`) - result = await service.searchChallenges(req.authUser, { ...req.query, ...req.body, legacyId }) - logger.debug(`Get mm challenge successfully`) + logger.debug(`Staring to get mm challengeId`); + const legacyId = await helper.getProjectIdByRoundId(req.query.legacyId); + logger.debug(`Get mm challengeId successfully ${legacyId}`); + result = await service.searchChallenges(req.authUser, { + ...req.query, + ...req.body, + legacyId, + }); + logger.debug(`Get mm challenge successfully`); } catch (e) { - logger.debug(`Failed to get projectId with error: ${e.message}`) + logger.debug(`Failed to get projectId with error: ${e.message}`); } } else { if (req.query.legacyId) { - logger.debug(`Skipped to get mm challenge`) + logger.debug(`Skipped to get mm challenge`); } } - helper.setResHeaders(req, res, result) - res.send(result.result) + helper.setResHeaders(req, res, result); + res.send(result.result); } /** @@ -39,10 +46,12 @@ async function searchChallenges (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function createChallenge (req, res) { - logger.debug(`createChallenge User: ${JSON.stringify(req.authUser)} - Body: ${JSON.stringify(req.body)}`) - const result = await service.createChallenge(req.authUser, req.body, req.userToken) - res.status(HttpStatus.CREATED).send(result) +async function createChallenge(req, res) { + logger.debug( + `createChallenge User: ${JSON.stringify(req.authUser)} - Body: ${JSON.stringify(req.body)}` + ); + const result = await service.createChallenge(req.authUser, req.body, req.userToken); + res.status(HttpStatus.CREATED).send(result); } /** @@ -50,9 +59,9 @@ async function createChallenge (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function sendNotifications (req, res) { - const result = await service.sendNotifications(req.authUser, req.params.challengeId) - res.status(HttpStatus.CREATED).send(result) +async function sendNotifications(req, res) { + const result = await service.sendNotifications(req.authUser, req.params.challengeId); + res.status(HttpStatus.CREATED).send(result); } /** @@ -60,9 +69,13 @@ async function sendNotifications (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function getChallenge (req, res) { - const result = await service.getChallenge(req.authUser, req.params.challengeId, req.query.checkIfExists) - res.send(result) +async function getChallenge(req, res) { + const result = await service.getChallenge( + req.authUser, + req.params.challengeId, + req.query.checkIfExists + ); + res.send(result); } /** @@ -70,20 +83,9 @@ async function getChallenge (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function getChallengeStatistics (req, res) { - const result = await service.getChallengeStatistics(req.authUser, req.params.challengeId) - res.send(result) -} - -/** - * Fully update challenge - * @param {Object} req the request - * @param {Object} res the response - */ -async function fullyUpdateChallenge (req, res) { - logger.debug(`fullyUpdateChallenge User: ${JSON.stringify(req.authUser)} - ChallengeID: ${req.params.challengeId} - Body: ${JSON.stringify(req.body)}`) - const result = await service.fullyUpdateChallenge(req.authUser, req.params.challengeId, req.body) - res.send(result) +async function getChallengeStatistics(req, res) { + const result = await service.getChallengeStatistics(req.authUser, req.params.challengeId); + res.send(result); } /** @@ -91,10 +93,14 @@ async function fullyUpdateChallenge (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function partiallyUpdateChallenge (req, res) { - logger.debug(`partiallyUpdateChallenge User: ${JSON.stringify(req.authUser)} - ChallengeID: ${req.params.challengeId} - Body: ${JSON.stringify(req.body)}`) - const result = await service.partiallyUpdateChallenge(req.authUser, req.params.challengeId, req.body) - res.send(result) +async function updateChallenge(req, res) { + logger.debug( + `updateChallenge User: ${JSON.stringify(req.authUser)} - ChallengeID: ${ + req.params.challengeId + } - Body: ${JSON.stringify(req.body)}` + ); + const result = await service.updateChallenge(req.authUser, req.params.challengeId, req.body); + res.send(result); } /** @@ -102,19 +108,20 @@ async function partiallyUpdateChallenge (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function deleteChallenge (req, res) { - logger.debug(`deleteChallenge User: ${JSON.stringify(req.authUser)} - ChallengeID: ${req.params.challengeId}`) - const result = await service.deleteChallenge(req.authUser, req.params.challengeId) - res.send(result) +async function deleteChallenge(req, res) { + logger.debug( + `deleteChallenge User: ${JSON.stringify(req.authUser)} - ChallengeID: ${req.params.challengeId}` + ); + const result = await service.deleteChallenge(req.authUser, req.params.challengeId); + res.send(result); } module.exports = { searchChallenges, createChallenge, getChallenge, - fullyUpdateChallenge, - partiallyUpdateChallenge, + updateChallenge, deleteChallenge, getChallengeStatistics, - sendNotifications -} + sendNotifications, +}; diff --git a/src/controllers/ChallengePhaseController.js b/src/controllers/ChallengePhaseController.js index d2f68118..c9b404f3 100644 --- a/src/controllers/ChallengePhaseController.js +++ b/src/controllers/ChallengePhaseController.js @@ -1,19 +1,19 @@ /** * Controller for challenge phase endpoints */ -const HttpStatus = require('http-status-codes') -const service = require('../services/PhaseService') -const helper = require('../common/helper') +const HttpStatus = require("http-status-codes"); +const service = require("../services/PhaseService"); +const helper = require("../common/helper"); /** * Search phases * @param {Object} req the request * @param {Object} res the response */ -async function searchPhases (req, res) { - const result = await service.searchPhases(req.query) - helper.setResHeaders(req, res, result) - res.send(result.result) +async function searchPhases(req, res) { + const result = await service.searchPhases(req.query); + helper.setResHeaders(req, res, result); + res.send(result.result); } /** @@ -21,9 +21,9 @@ async function searchPhases (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function createPhase (req, res) { - const result = await service.createPhase(req.body) - res.status(HttpStatus.CREATED).send(result) +async function createPhase(req, res) { + const result = await service.createPhase(req.body); + res.status(HttpStatus.CREATED).send(result); } /** @@ -31,9 +31,9 @@ async function createPhase (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function getPhase (req, res) { - const result = await service.getPhase(req.params.challengePhaseId) - res.send(result) +async function getPhase(req, res) { + const result = await service.getPhase(req.params.challengePhaseId); + res.send(result); } /** @@ -41,9 +41,12 @@ async function getPhase (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function fullyUpdatePhase (req, res) { - const result = await service.fullyUpdatePhase(req.params.challengePhaseId, req.body) - res.send(result) +async function fullyUpdatePhase(req, res) { + const result = await service.fullyUpdatePhase( + req.params.challengePhaseId, + req.body + ); + res.send(result); } /** @@ -51,9 +54,12 @@ async function fullyUpdatePhase (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function partiallyUpdatePhase (req, res) { - const result = await service.partiallyUpdatePhase(req.params.challengePhaseId, req.body) - res.send(result) +async function partiallyUpdatePhase(req, res) { + const result = await service.partiallyUpdatePhase( + req.params.challengePhaseId, + req.body + ); + res.send(result); } /** @@ -61,9 +67,9 @@ async function partiallyUpdatePhase (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function deletePhase (req, res) { - const result = await service.deletePhase(req.params.challengePhaseId) - res.send(result) +async function deletePhase(req, res) { + const result = await service.deletePhase(req.params.challengePhaseId); + res.send(result); } module.exports = { @@ -72,5 +78,5 @@ module.exports = { getPhase, fullyUpdatePhase, partiallyUpdatePhase, - deletePhase -} + deletePhase, +}; diff --git a/src/controllers/ChallengeTimelineTemplateController.js b/src/controllers/ChallengeTimelineTemplateController.js index 28eb54bb..9fb3ac76 100644 --- a/src/controllers/ChallengeTimelineTemplateController.js +++ b/src/controllers/ChallengeTimelineTemplateController.js @@ -1,19 +1,19 @@ /** * Controller for challenge type timeline templates endpoints */ -const HttpStatus = require('http-status-codes') -const service = require('../services/ChallengeTimelineTemplateService') -const helper = require('../common/helper') +const HttpStatus = require("http-status-codes"); +const service = require("../services/ChallengeTimelineTemplateService"); +const helper = require("../common/helper"); /** * Search challenge type timeline templates. * @param {Object} req the request * @param {Object} res the response */ -async function searchChallengeTimelineTemplates (req, res) { - const result = await service.searchChallengeTimelineTemplates(req.query) - helper.setResHeaders(req, res, result) - res.send(result.result) +async function searchChallengeTimelineTemplates(req, res) { + const result = await service.searchChallengeTimelineTemplates(req.query); + helper.setResHeaders(req, res, result); + res.send(result.result); } /** @@ -21,9 +21,9 @@ async function searchChallengeTimelineTemplates (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function createChallengeTimelineTemplate (req, res) { - const result = await service.createChallengeTimelineTemplate(req.body) - res.status(HttpStatus.CREATED).send(result) +async function createChallengeTimelineTemplate(req, res) { + const result = await service.createChallengeTimelineTemplate(req.body); + res.status(HttpStatus.CREATED).send(result); } /** @@ -31,9 +31,11 @@ async function createChallengeTimelineTemplate (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function getChallengeTimelineTemplate (req, res) { - const result = await service.getChallengeTimelineTemplate(req.params.challengeTimelineTemplateId) - res.send(result) +async function getChallengeTimelineTemplate(req, res) { + const result = await service.getChallengeTimelineTemplate( + req.params.challengeTimelineTemplateId + ); + res.send(result); } /** @@ -41,9 +43,12 @@ async function getChallengeTimelineTemplate (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function fullyUpdateChallengeTimelineTemplate (req, res) { - const result = await service.fullyUpdateChallengeTimelineTemplate(req.params.challengeTimelineTemplateId, req.body) - res.send(result) +async function fullyUpdateChallengeTimelineTemplate(req, res) { + const result = await service.fullyUpdateChallengeTimelineTemplate( + req.params.challengeTimelineTemplateId, + req.body + ); + res.send(result); } /** @@ -51,9 +56,11 @@ async function fullyUpdateChallengeTimelineTemplate (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function deleteChallengeTimelineTemplate (req, res) { - const result = await service.deleteChallengeTimelineTemplate(req.params.challengeTimelineTemplateId) - res.send(result) +async function deleteChallengeTimelineTemplate(req, res) { + const result = await service.deleteChallengeTimelineTemplate( + req.params.challengeTimelineTemplateId + ); + res.send(result); } module.exports = { @@ -61,5 +68,5 @@ module.exports = { createChallengeTimelineTemplate, getChallengeTimelineTemplate, fullyUpdateChallengeTimelineTemplate, - deleteChallengeTimelineTemplate -} + deleteChallengeTimelineTemplate, +}; diff --git a/src/controllers/ChallengeTrackController.js b/src/controllers/ChallengeTrackController.js index 6e795362..cac350f1 100644 --- a/src/controllers/ChallengeTrackController.js +++ b/src/controllers/ChallengeTrackController.js @@ -1,19 +1,19 @@ /** * Controller for challenge type endpoints */ -const HttpStatus = require('http-status-codes') -const service = require('../services/ChallengeTrackService') -const helper = require('../common/helper') +const HttpStatus = require("http-status-codes"); +const service = require("../services/ChallengeTrackService"); +const helper = require("../common/helper"); /** * Search challenge types * @param {Object} req the request * @param {Object} res the response */ -async function searchChallengeTracks (req, res) { - const result = await service.searchChallengeTracks(req.query) - helper.setResHeaders(req, res, result) - res.send(result.result) +async function searchChallengeTracks(req, res) { + const result = await service.searchChallengeTracks(req.query); + helper.setResHeaders(req, res, result); + res.send(result.result); } /** @@ -21,9 +21,9 @@ async function searchChallengeTracks (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function createChallengeTrack (req, res) { - const result = await service.createChallengeTrack(req.body) - res.status(HttpStatus.CREATED).send(result) +async function createChallengeTrack(req, res) { + const result = await service.createChallengeTrack(req.body); + res.status(HttpStatus.CREATED).send(result); } /** @@ -31,9 +31,9 @@ async function createChallengeTrack (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function getChallengeTrack (req, res) { - const result = await service.getChallengeTrack(req.params.challengeTrackId) - res.send(result) +async function getChallengeTrack(req, res) { + const result = await service.getChallengeTrack(req.params.challengeTrackId); + res.send(result); } /** @@ -41,9 +41,9 @@ async function getChallengeTrack (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function fullyUpdateChallengeTrack (req, res) { - const result = await service.fullyUpdateChallengeTrack(req.params.challengeTrackId, req.body) - res.send(result) +async function fullyUpdateChallengeTrack(req, res) { + const result = await service.fullyUpdateChallengeTrack(req.params.challengeTrackId, req.body); + res.send(result); } /** @@ -51,9 +51,9 @@ async function fullyUpdateChallengeTrack (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function partiallyUpdateChallengeTrack (req, res) { - const result = await service.partiallyUpdateChallengeTrack(req.params.challengeTrackId, req.body) - res.send(result) +async function partiallyUpdateChallengeTrack(req, res) { + const result = await service.partiallyUpdateChallengeTrack(req.params.challengeTrackId, req.body); + res.send(result); } /** @@ -61,9 +61,9 @@ async function partiallyUpdateChallengeTrack (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function deleteChallengeTrack (req, res) { - const result = await service.deleteChallengeTrack(req.params.challengeTrackId) - res.send(result) +async function deleteChallengeTrack(req, res) { + const result = await service.deleteChallengeTrack(req.params.challengeTrackId); + res.send(result); } module.exports = { @@ -72,5 +72,5 @@ module.exports = { getChallengeTrack, fullyUpdateChallengeTrack, partiallyUpdateChallengeTrack, - deleteChallengeTrack -} + deleteChallengeTrack, +}; diff --git a/src/controllers/ChallengeTypeController.js b/src/controllers/ChallengeTypeController.js index 85d529f2..dd6b6fc2 100644 --- a/src/controllers/ChallengeTypeController.js +++ b/src/controllers/ChallengeTypeController.js @@ -1,19 +1,19 @@ /** * Controller for challenge type endpoints */ -const HttpStatus = require('http-status-codes') -const service = require('../services/ChallengeTypeService') -const helper = require('../common/helper') +const HttpStatus = require("http-status-codes"); +const service = require("../services/ChallengeTypeService"); +const helper = require("../common/helper"); /** * Search challenge types * @param {Object} req the request * @param {Object} res the response */ -async function searchChallengeTypes (req, res) { - const result = await service.searchChallengeTypes(req.query) - helper.setResHeaders(req, res, result) - res.send(result.result) +async function searchChallengeTypes(req, res) { + const result = await service.searchChallengeTypes(req.query); + helper.setResHeaders(req, res, result); + res.send(result.result); } /** @@ -21,9 +21,9 @@ async function searchChallengeTypes (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function createChallengeType (req, res) { - const result = await service.createChallengeType(req.body) - res.status(HttpStatus.CREATED).send(result) +async function createChallengeType(req, res) { + const result = await service.createChallengeType(req.body); + res.status(HttpStatus.CREATED).send(result); } /** @@ -31,9 +31,9 @@ async function createChallengeType (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function getChallengeType (req, res) { - const result = await service.getChallengeType(req.params.challengeTypeId) - res.send(result) +async function getChallengeType(req, res) { + const result = await service.getChallengeType(req.params.challengeTypeId); + res.send(result); } /** @@ -41,9 +41,9 @@ async function getChallengeType (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function fullyUpdateChallengeType (req, res) { - const result = await service.fullyUpdateChallengeType(req.params.challengeTypeId, req.body) - res.send(result) +async function fullyUpdateChallengeType(req, res) { + const result = await service.fullyUpdateChallengeType(req.params.challengeTypeId, req.body); + res.send(result); } /** @@ -51,9 +51,9 @@ async function fullyUpdateChallengeType (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function partiallyUpdateChallengeType (req, res) { - const result = await service.partiallyUpdateChallengeType(req.params.challengeTypeId, req.body) - res.send(result) +async function partiallyUpdateChallengeType(req, res) { + const result = await service.partiallyUpdateChallengeType(req.params.challengeTypeId, req.body); + res.send(result); } /** @@ -61,9 +61,9 @@ async function partiallyUpdateChallengeType (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function deleteChallengeType (req, res) { - const result = await service.deleteChallengeType(req.params.challengeTypeId) - res.send(result) +async function deleteChallengeType(req, res) { + const result = await service.deleteChallengeType(req.params.challengeTypeId); + res.send(result); } module.exports = { @@ -72,5 +72,5 @@ module.exports = { getChallengeType, fullyUpdateChallengeType, partiallyUpdateChallengeType, - deleteChallengeType -} + deleteChallengeType, +}; diff --git a/src/controllers/HealthController.js b/src/controllers/HealthController.js index 6c7dafa4..c07d03a0 100644 --- a/src/controllers/HealthController.js +++ b/src/controllers/HealthController.js @@ -1,37 +1,42 @@ /** * Controller for health check endpoint */ -const config = require('config') -const service = require('../services/ChallengeTypeService') -const errors = require('../common/errors') +const config = require("config"); +const service = require("../services/ChallengeTypeService"); +const errors = require("../common/errors"); // the topcoder-healthcheck-dropin library returns checksRun count, // here it follows that to return such count -let checksRun = 0 +let checksRun = 0; /** * Check health of the app * @param {Object} req the request * @param {Object} res the response */ -async function checkHealth (req, res) { +async function checkHealth(req, res) { // perform a quick database access operation, if there is no error and is quick, then consider it healthy; // there are just a few challenge types, so search challenge types should be efficient operation, // and it just searches a single challenge type, it should be quick operation - checksRun += 1 - const timestampMS = new Date().getTime() + checksRun += 1; + const timestampMS = new Date().getTime(); try { - await service.searchChallengeTypes({ page: 1, perPage: 1 }) + await service.searchChallengeTypes({ page: 1, perPage: 1 }); } catch (e) { - throw new errors.ServiceUnavailableError(`There is database operation error, ${e.message}`) + throw new errors.ServiceUnavailableError( + `There is database operation error, ${e.message}` + ); } - if (new Date().getTime() - timestampMS > Number(config.HEALTH_CHECK_TIMEOUT)) { - throw new errors.ServiceUnavailableError('Database operation is slow.') + if ( + new Date().getTime() - timestampMS > + Number(config.HEALTH_CHECK_TIMEOUT) + ) { + throw new errors.ServiceUnavailableError("Database operation is slow."); } // there is no error, and it is quick, then return checks run count - res.send({ checksRun }) + res.send({ checksRun }); } module.exports = { - checkHealth -} + checkHealth, +}; diff --git a/src/controllers/SupportController.js b/src/controllers/SupportController.js index 07aa69fb..87b06fa4 100644 --- a/src/controllers/SupportController.js +++ b/src/controllers/SupportController.js @@ -1,21 +1,25 @@ /** * Controller for support endpoints */ -const HttpStatus = require('http-status-codes') -const service = require('../services/SupportService') -const logger = require('../common/logger') +const HttpStatus = require("http-status-codes"); +const service = require("../services/SupportService"); +const logger = require("../common/logger"); /** * Create challenge * @param {Object} req the request * @param {Object} res the response */ -async function createRequest (req, res) { - logger.debug(`createRequest User: ${JSON.stringify(req.authUser)} - Body: ${JSON.stringify(req.body)}`) - const result = await service.createRequest(req.authUser, req.body) - res.status(HttpStatus.CREATED).send(result) +async function createRequest(req, res) { + logger.debug( + `createRequest User: ${JSON.stringify( + req.authUser + )} - Body: ${JSON.stringify(req.body)}` + ); + const result = await service.createRequest(req.authUser, req.body); + res.status(HttpStatus.CREATED).send(result); } module.exports = { - createRequest -} + createRequest, +}; diff --git a/src/controllers/TimelineTemplateController.js b/src/controllers/TimelineTemplateController.js index cc77c918..e17e140c 100644 --- a/src/controllers/TimelineTemplateController.js +++ b/src/controllers/TimelineTemplateController.js @@ -1,19 +1,19 @@ /** * Controller for challenge phase endpoints */ -const HttpStatus = require('http-status-codes') -const service = require('../services/TimelineTemplateService') -const helper = require('../common/helper') +const HttpStatus = require("http-status-codes"); +const service = require("../services/TimelineTemplateService"); +const helper = require("../common/helper"); /** * Search timeline templates. * @param {Object} req the request * @param {Object} res the response */ -async function searchTimelineTemplates (req, res) { - const result = await service.searchTimelineTemplates(req.query) - helper.setResHeaders(req, res, result) - res.send(result.result) +async function searchTimelineTemplates(req, res) { + const result = await service.searchTimelineTemplates(req.query); + helper.setResHeaders(req, res, result); + res.send(result.result); } /** @@ -21,9 +21,9 @@ async function searchTimelineTemplates (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function createTimelineTemplate (req, res) { - const result = await service.createTimelineTemplate(req.body) - res.status(HttpStatus.CREATED).send(result) +async function createTimelineTemplate(req, res) { + const result = await service.createTimelineTemplate(req.body); + res.status(HttpStatus.CREATED).send(result); } /** @@ -31,9 +31,11 @@ async function createTimelineTemplate (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function getTimelineTemplate (req, res) { - const result = await service.getTimelineTemplate(req.params.timelineTemplateId) - res.send(result) +async function getTimelineTemplate(req, res) { + const result = await service.getTimelineTemplate( + req.params.timelineTemplateId + ); + res.send(result); } /** @@ -41,9 +43,12 @@ async function getTimelineTemplate (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function fullyUpdateTimelineTemplate (req, res) { - const result = await service.fullyUpdateTimelineTemplate(req.params.timelineTemplateId, req.body) - res.send(result) +async function fullyUpdateTimelineTemplate(req, res) { + const result = await service.fullyUpdateTimelineTemplate( + req.params.timelineTemplateId, + req.body + ); + res.send(result); } /** @@ -51,9 +56,12 @@ async function fullyUpdateTimelineTemplate (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function partiallyUpdateTimelineTemplate (req, res) { - const result = await service.partiallyUpdateTimelineTemplate(req.params.timelineTemplateId, req.body) - res.send(result) +async function partiallyUpdateTimelineTemplate(req, res) { + const result = await service.partiallyUpdateTimelineTemplate( + req.params.timelineTemplateId, + req.body + ); + res.send(result); } /** @@ -61,9 +69,11 @@ async function partiallyUpdateTimelineTemplate (req, res) { * @param {Object} req the request * @param {Object} res the response */ -async function deleteTimelineTemplate (req, res) { - const result = await service.deleteTimelineTemplate(req.params.timelineTemplateId) - res.send(result) +async function deleteTimelineTemplate(req, res) { + const result = await service.deleteTimelineTemplate( + req.params.timelineTemplateId + ); + res.send(result); } module.exports = { @@ -72,5 +82,5 @@ module.exports = { getTimelineTemplate, fullyUpdateTimelineTemplate, partiallyUpdateTimelineTemplate, - deleteTimelineTemplate -} + deleteTimelineTemplate, +}; diff --git a/src/init-es.js b/src/init-es.js index 1b5f8a40..e0f055d9 100644 --- a/src/init-es.js +++ b/src/init-es.js @@ -6,103 +6,111 @@ * node src/init-es * node src/init-es force */ -const config = require('config') -const logger = require('./common/logger') -const helper = require('./common/helper') +const config = require("config"); +const logger = require("./common/logger"); +const helper = require("./common/helper"); -const client = helper.getESClient() +const client = helper.getESClient(); const initES = async () => { - if (process.argv.length === 3 && process.argv[2] === 'force') { - logger.info(`Delete index ${config.ES.ES_INDEX} if any.`) + if (process.argv.length === 3 && process.argv[2] === "force") { + logger.info(`Delete index ${config.ES.ES_INDEX} if any.`); try { - await client.indices.delete({ index: config.ES.ES_INDEX }) + await client.indices.delete({ index: config.ES.ES_INDEX }); } catch (err) { // ignore } } - const exists = await client.indices.exists({ index: config.ES.ES_INDEX }) + const { body: exists } = await client.indices.exists({ index: config.ES.ES_INDEX }); if (exists) { - logger.info(`The index ${config.ES.ES_INDEX} exists.`) + logger.info(`The index ${config.ES.ES_INDEX} exists.`); } else { - logger.info(`The index ${config.ES.ES_INDEX} will be created.`) + logger.info(`The index ${config.ES.ES_INDEX} will be created.`); - const body = { mappings: {} } - body.mappings[config.get('ES.ES_TYPE')] = { - properties: { - id: { type: 'keyword' }, - name: { - type: 'keyword', - fields: { - text: { - type: 'text' - } + const body = { + mappings: { + // properties: { + properties: { + id: { type: "keyword" }, + name: { + type: "keyword", + fields: { + text: { + type: "text", + }, + }, + normalizer: "custom_sort_normalizer", }, - normalizer: 'custom_sort_normalizer' - }, - status: { - type: 'keyword', - fields: { - text: { - type: 'text' - } + status: { + type: "keyword", + fields: { + text: { + type: "text", + }, + }, + normalizer: "custom_sort_normalizer", }, - normalizer: 'custom_sort_normalizer' - }, - type: { - type: 'keyword', - fields: { - text: { - type: 'text' - } + type: { + type: "keyword", + fields: { + text: { + type: "text", + }, + }, + normalizer: "custom_sort_normalizer", + }, + prizeSets: { + properties: { + type: { type: "text" }, + prizes: { + properties: { + type: { type: "text" }, + value: { type: "float" }, + }, + }, + }, }, - normalizer: 'custom_sort_normalizer' }, - prizeSets: { - properties: { - type: { type: 'text' }, - prizes: { - properties: { - type: { type: 'text' }, - value: { type: 'float' } - } - } - } - } + dynamic_templates: [ + { + metadata: { + path_match: "metadata.*", + mapping: { + type: "text", + }, + }, + }, + ], + //} }, - dynamic_templates: [{ - metadata: { - path_match: 'metadata.*', - mapping: { - type: 'text' - } - } - }] - } + }; + body.settings = { analysis: { normalizer: { custom_sort_normalizer: { - type: 'custom', + type: "custom", char_filter: [], - filter: ['lowercase', 'asciifolding'] - } - } - } - } + filter: ["lowercase", "asciifolding"], + }, + }, + }, + }; await client.indices.create({ index: config.ES.ES_INDEX, - body - }) + body, + }); } -} +}; -initES().then(() => { - logger.info('Done!') - process.exit() -}).catch((e) => { - logger.logFullError(e) - process.exit() -}) +initES() + .then(() => { + logger.info("Done!"); + process.exit(); + }) + .catch((e) => { + logger.logFullError(e); + process.exit(); + }); diff --git a/src/models/Attachment.js b/src/models/Attachment.js index 0eee2a87..fa89cb74 100644 --- a/src/models/Attachment.js +++ b/src/models/Attachment.js @@ -2,38 +2,40 @@ * This defines Attachment model. */ -const dynamoose = require('dynamoose') +const dynamoose = require("dynamoose"); -const Schema = dynamoose.Schema +const Schema = dynamoose.Schema; -const schema = new Schema({ - id: { - type: String, - hashKey: true, - required: true +const schema = new Schema( + { + id: { + type: String, + hashKey: true, + required: true, + }, + url: { + type: String, + required: true, + }, + fileSize: { + type: Number, + required: true, + }, + name: { + type: String, + required: true, + }, + challengeId: { + type: String, + required: true, + }, + description: { + type: String, + }, }, - url: { - type: String, - required: true - }, - fileSize: { - type: Number, - required: true - }, - name: { - type: String, - required: true - }, - challengeId: { - type: String, - required: true - }, - description: { - type: String + { + throughput: { read: 4, write: 2 }, } -}, -{ - throughput: { read: 4, write: 2 } -}) +); -module.exports = schema +module.exports = schema; diff --git a/src/models/AuditLog.js b/src/models/AuditLog.js index 3158ac32..48e884a4 100644 --- a/src/models/AuditLog.js +++ b/src/models/AuditLog.js @@ -2,46 +2,48 @@ * This defines AuditLog model. */ -const dynamoose = require('dynamoose') +const dynamoose = require("dynamoose"); -const Schema = dynamoose.Schema +const Schema = dynamoose.Schema; -const schema = new Schema({ - id: { - type: String, - hashKey: true, - required: true +const schema = new Schema( + { + id: { + type: String, + hashKey: true, + required: true, + }, + challengeId: { + type: String, + required: true, + }, + fieldName: { + type: String, + required: true, + }, + oldValue: { + type: String, + required: true, + }, + newValue: { + type: String, + required: true, + }, + created: { + type: Date, + required: true, + }, + createdBy: { + type: String, + required: true, + }, + memberId: { + type: String, + }, }, - challengeId: { - type: String, - required: true - }, - fieldName: { - type: String, - required: true - }, - oldValue: { - type: String, - required: true - }, - newValue: { - type: String, - required: true - }, - created: { - type: Date, - required: true - }, - createdBy: { - type: String, - required: true - }, - memberId: { - type: String + { + throughput: { read: 4, write: 2 }, } -}, -{ - throughput: { read: 4, write: 2 } -}) +); -module.exports = schema +module.exports = schema; diff --git a/src/models/Challenge.js b/src/models/Challenge.js index 5aec842f..326d2dce 100644 --- a/src/models/Challenge.js +++ b/src/models/Challenge.js @@ -2,145 +2,146 @@ * This defines Challenge model. */ -const dynamoose = require('dynamoose') +const dynamoose = require("dynamoose"); -const Schema = dynamoose.Schema +const Schema = dynamoose.Schema; -const schema = new Schema({ - id: { - type: String, - hashKey: true, - required: true - }, - legacyId: { - type: Number, - required: false - }, - typeId: { - type: String, - required: true - }, - trackId: { - type: String, - required: true - }, - legacy: { - type: Object, - required: false - }, - billing: { - type: Object, - required: false - }, - name: { - type: String, - required: true - }, - description: { - type: String, - required: false - }, - privateDescription: { - type: String, - required: false - }, - descriptionFormat: { - type: String, - default: 'HTML', - required: true - }, - metadata: { - type: [Object], - required: false - }, - task: { - type: Object, - required: false - }, - timelineTemplateId: { - type: String, - required: false - }, - phases: { - type: Array, - required: false - }, - events: { - type: [Object], - required: false - }, - terms: { - type: Array, - required: false - }, - prizeSets: { - type: [Object], - required: false - }, - // tag names - tags: { - type: Array, - required: false - }, - projectId: { - type: Number, - required: false - }, - startDate: { - type: Date, - required: false - }, - endDate: { - type: Date, - required: false - }, - status: { - type: String, - required: true - }, - attachments: { - type: Array, - required: false - }, - // group names - groups: { - type: Array, - required: false - }, - // winners - winners: { - type: Array, - required: false - }, - discussions: { - type: [Object], - required: false - }, - overview: { - type: Object - }, - created: { - type: Date, - required: true - }, - createdBy: { - type: String, - required: true - }, - updated: { - type: Date, - required: false - }, - updatedBy: { - type: String, - required: false +const schema = new Schema( + { + id: { + type: String, + hashKey: true, + required: true, + }, + legacyId: { + type: Number, + required: false, + }, + typeId: { + type: String, + required: true, + }, + trackId: { + type: String, + required: true, + }, + legacy: { + type: Object, + required: false, + }, + billing: { + type: Object, + required: false, + }, + name: { + type: String, + required: true, + }, + description: { + type: String, + required: false, + }, + privateDescription: { + type: String, + required: false, + }, + descriptionFormat: { + type: String, + default: "HTML", + required: true, + }, + metadata: { + type: [Object], + required: false, + }, + task: { + type: Object, + required: false, + }, + timelineTemplateId: { + type: String, + required: false, + }, + phases: { + type: Array, + required: false, + }, + events: { + type: [Object], + required: false, + }, + terms: { + type: Array, + required: false, + }, + prizeSets: { + type: [Object], + required: false, + }, + // tag names + tags: { + type: Array, + required: false, + }, + projectId: { + type: Number, + required: false, + }, + startDate: { + type: Date, + required: false, + }, + endDate: { + type: Date, + required: false, + }, + status: { + type: String, + required: true, + }, + attachments: { + type: Array, + required: false, + }, + // group names + groups: { + type: Array, + required: false, + }, + // winners + winners: { + type: Array, + required: false, + }, + discussions: { + type: [Object], + required: false, + }, + overview: { + type: Object, + }, + created: { + type: Date, + required: true, + }, + createdBy: { + type: String, + required: true, + }, + updated: { + type: Date, + required: false, + }, + updatedBy: { + type: String, + required: false, + }, + }, + { + // throughput: { read: 4, write: 2 }, + throughput: "ON_DEMAND", + useDocumentTypes: true, } -}, -{ - // throughput: { read: 4, write: 2 }, - throughput: 'ON_DEMAND', - useDocumentTypes: true -} -) +); -module.exports = schema +module.exports = schema; diff --git a/src/models/ChallengeTimelineTemplate.js b/src/models/ChallengeTimelineTemplate.js index 881e521e..7637b489 100644 --- a/src/models/ChallengeTimelineTemplate.js +++ b/src/models/ChallengeTimelineTemplate.js @@ -2,35 +2,37 @@ * This defines ChallengeType-TimelineTemplate mapping model. */ -const dynamoose = require('dynamoose') +const dynamoose = require("dynamoose"); -const Schema = dynamoose.Schema +const Schema = dynamoose.Schema; -const schema = new Schema({ - id: { - type: String, - hashKey: true, - required: true +const schema = new Schema( + { + id: { + type: String, + hashKey: true, + required: true, + }, + trackId: { + type: String, + required: true, + }, + typeId: { + type: String, + required: true, + }, + timelineTemplateId: { + type: String, + required: true, + }, + isDefault: { + type: Boolean, + required: false, + }, }, - trackId: { - type: String, - required: true - }, - typeId: { - type: String, - required: true - }, - timelineTemplateId: { - type: String, - required: true - }, - isDefault: { - type: Boolean, - required: false + { + throughput: { read: 4, write: 2 }, } -}, -{ - throughput: { read: 4, write: 2 } -}) +); -module.exports = schema +module.exports = schema; diff --git a/src/models/ChallengeTrack.js b/src/models/ChallengeTrack.js index 908e029e..7decc695 100644 --- a/src/models/ChallengeTrack.js +++ b/src/models/ChallengeTrack.js @@ -2,35 +2,37 @@ * This defines ChallengeTrack model. */ -const dynamoose = require('dynamoose') +const dynamoose = require("dynamoose"); -const Schema = dynamoose.Schema +const Schema = dynamoose.Schema; -const schema = new Schema({ - id: { - type: String, - hashKey: true, - required: true +const schema = new Schema( + { + id: { + type: String, + hashKey: true, + required: true, + }, + name: { + type: String, + required: true, + }, + description: { + type: String, + required: false, + }, + isActive: { + type: Boolean, + required: true, + }, + abbreviation: { + type: String, + required: true, + }, }, - name: { - type: String, - required: true - }, - description: { - type: String, - required: false - }, - isActive: { - type: Boolean, - required: true - }, - abbreviation: { - type: String, - required: true + { + throughput: { read: 4, write: 2 }, } -}, -{ - throughput: { read: 4, write: 2 } -}) +); -module.exports = schema +module.exports = schema; diff --git a/src/models/ChallengeType.js b/src/models/ChallengeType.js index d96e022a..16917e0b 100644 --- a/src/models/ChallengeType.js +++ b/src/models/ChallengeType.js @@ -2,39 +2,41 @@ * This defines ChallengeType model. */ -const dynamoose = require('dynamoose') +const dynamoose = require("dynamoose"); -const Schema = dynamoose.Schema +const Schema = dynamoose.Schema; -const schema = new Schema({ - id: { - type: String, - hashKey: true, - required: true +const schema = new Schema( + { + id: { + type: String, + hashKey: true, + required: true, + }, + name: { + type: String, + required: true, + }, + description: { + type: String, + required: false, + }, + isActive: { + type: Boolean, + required: true, + }, + isTask: { + type: Boolean, + default: false, + }, + abbreviation: { + type: String, + required: true, + }, }, - name: { - type: String, - required: true - }, - description: { - type: String, - required: false - }, - isActive: { - type: Boolean, - required: true - }, - isTask: { - type: Boolean, - default: false - }, - abbreviation: { - type: String, - required: true + { + throughput: { read: 4, write: 2 }, } -}, -{ - throughput: { read: 4, write: 2 } -}) +); -module.exports = schema +module.exports = schema; diff --git a/src/models/Phase.js b/src/models/Phase.js index 4fdf56ad..c0974ba3 100644 --- a/src/models/Phase.js +++ b/src/models/Phase.js @@ -2,36 +2,38 @@ * This defines Phase model. */ -const dynamoose = require('dynamoose') +const dynamoose = require("dynamoose"); -const Schema = dynamoose.Schema +const Schema = dynamoose.Schema; -const schema = new Schema({ - id: { - type: String, - hashKey: true, - required: true +const schema = new Schema( + { + id: { + type: String, + hashKey: true, + required: true, + }, + name: { + type: String, + required: true, + }, + description: { + type: String, + required: false, + }, + isOpen: { + type: Boolean, + required: true, + }, + duration: { + type: Number, + required: true, + }, }, - name: { - type: String, - required: true - }, - description: { - type: String, - required: false - }, - isOpen: { - type: Boolean, - required: true - }, - duration: { - type: Number, - required: true + { + throughput: "ON_DEMAND", + // throughput: { read: 4, write: 2 } } -}, -{ - throughput: 'ON_DEMAND' - // throughput: { read: 4, write: 2 } -}) +); -module.exports = schema +module.exports = schema; diff --git a/src/models/TimelineTemplate.js b/src/models/TimelineTemplate.js index fe40c605..157297ef 100644 --- a/src/models/TimelineTemplate.js +++ b/src/models/TimelineTemplate.js @@ -2,35 +2,37 @@ * This defines TimelineTemplate model. */ -const dynamoose = require('dynamoose') +const dynamoose = require("dynamoose"); -const Schema = dynamoose.Schema +const Schema = dynamoose.Schema; -const schema = new Schema({ - id: { - type: String, - hashKey: true, - required: true +const schema = new Schema( + { + id: { + type: String, + hashKey: true, + required: true, + }, + name: { + type: String, + required: true, + }, + description: { + type: String, + required: false, + }, + isActive: { + type: Boolean, + required: true, + }, + phases: { + type: Array, + required: true, + }, }, - name: { - type: String, - required: true - }, - description: { - type: String, - required: false - }, - isActive: { - type: Boolean, - required: true - }, - phases: { - type: Array, - required: true + { + throughput: { read: 4, write: 2 }, } -}, -{ - throughput: { read: 4, write: 2 } -}) +); -module.exports = schema +module.exports = schema; diff --git a/src/models/index.js b/src/models/index.js index 8a006613..489c0527 100644 --- a/src/models/index.js +++ b/src/models/index.js @@ -2,21 +2,23 @@ * Initialize and export all model schemas. */ -const config = require('config') -const dynamoose = require('dynamoose') +const config = require("config"); +const dynamoose = require("dynamoose"); -const awsConfigs = config.AMAZON.IS_LOCAL_DB ? { - accessKeyId: config.AMAZON.AWS_ACCESS_KEY_ID, - secretAccessKey: config.AMAZON.AWS_SECRET_ACCESS_KEY, - region: config.AMAZON.AWS_REGION -} : { - region: config.AMAZON.AWS_REGION -} +const awsConfigs = config.AMAZON.IS_LOCAL_DB + ? { + accessKeyId: config.AMAZON.AWS_ACCESS_KEY_ID, + secretAccessKey: config.AMAZON.AWS_SECRET_ACCESS_KEY, + region: config.AMAZON.AWS_REGION, + } + : { + region: config.AMAZON.AWS_REGION, + }; -dynamoose.AWS.config.update(awsConfigs) +dynamoose.AWS.config.update(awsConfigs); if (config.AMAZON.IS_LOCAL_DB) { - dynamoose.local(config.AMAZON.DYNAMODB_URL) + dynamoose.local(config.AMAZON.DYNAMODB_URL); } // console.log(config.AMAZON.IS_LOCAL_DB, config.AMAZON.AWS_ACCESS_KEY_ID, config.AMAZON.AWS_SECRET_ACCESS_KEY) @@ -25,16 +27,25 @@ if (config.AMAZON.IS_LOCAL_DB) { dynamoose.setDefaults({ create: false, update: false, - waitForActive: false -}) + waitForActive: false, +}); module.exports = { - Challenge: dynamoose.model('Challenge', require('./Challenge')), - ChallengeType: dynamoose.model('ChallengeType', require('./ChallengeType')), - ChallengeTrack: dynamoose.model('ChallengeTrack', require('./ChallengeTrack')), - ChallengeTimelineTemplate: dynamoose.model('ChallengeTimelineTemplate', require('./ChallengeTimelineTemplate')), - AuditLog: dynamoose.model('AuditLog', require('./AuditLog')), - Phase: dynamoose.model('Phase', require('./Phase')), - TimelineTemplate: dynamoose.model('TimelineTemplate', require('./TimelineTemplate')), - Attachment: dynamoose.model('Attachment', require('./Attachment')) -} + Challenge: dynamoose.model("Challenge", require("./Challenge")), + ChallengeType: dynamoose.model("ChallengeType", require("./ChallengeType")), + ChallengeTrack: dynamoose.model( + "ChallengeTrack", + require("./ChallengeTrack") + ), + ChallengeTimelineTemplate: dynamoose.model( + "ChallengeTimelineTemplate", + require("./ChallengeTimelineTemplate") + ), + AuditLog: dynamoose.model("AuditLog", require("./AuditLog")), + Phase: dynamoose.model("Phase", require("./Phase")), + TimelineTemplate: dynamoose.model( + "TimelineTemplate", + require("./TimelineTemplate") + ), + Attachment: dynamoose.model("Attachment", require("./Attachment")), +}; diff --git a/src/routes.js b/src/routes.js index 5a2b98cd..407b7a41 100644 --- a/src/routes.js +++ b/src/routes.js @@ -2,346 +2,372 @@ * Contains all routes */ -const constants = require('../app-constants') -const { SCOPES: { - READ, - CREATE, - UPDATE, - DELETE, - ALL -} } = require('config') +const constants = require("../app-constants"); +const { + SCOPES: { READ, CREATE, UPDATE, DELETE, ALL }, +} = require("config"); module.exports = { - '/challenges': { + "/challenges": { get: { - controller: 'ChallengeController', - method: 'searchChallenges', - access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.SelfServiceCustomer, constants.UserRoles.Manager, constants.UserRoles.User], - scopes: [READ, ALL] + controller: "ChallengeController", + method: "searchChallenges", + access: [ + constants.UserRoles.Admin, + constants.UserRoles.Copilot, + constants.UserRoles.SelfServiceCustomer, + constants.UserRoles.Manager, + constants.UserRoles.User, + ], + scopes: [READ, ALL], }, post: { - controller: 'ChallengeController', - method: 'createChallenge', - auth: 'jwt', - access: [constants.UserRoles.Admin, constants.UserRoles.SelfServiceCustomer, constants.UserRoles.Copilot, constants.UserRoles.Manager, constants.UserRoles.User], - scopes: [CREATE, ALL] - } + controller: "ChallengeController", + method: "createChallenge", + auth: "jwt", + access: [ + constants.UserRoles.Admin, + constants.UserRoles.SelfServiceCustomer, + constants.UserRoles.Copilot, + constants.UserRoles.Manager, + constants.UserRoles.User, + ], + scopes: [CREATE, ALL], + }, }, - '/challenges/support-requests': { + "/challenges/support-requests": { post: { - controller: 'SupportController', - method: 'createRequest' - } + controller: "SupportController", + method: "createRequest", + }, }, - '/challenges/health': { + "/challenges/health": { get: { - controller: 'HealthController', - method: 'checkHealth' - } + controller: "HealthController", + method: "checkHealth", + }, }, - '/challenges/:challengeId': { + "/challenges/:challengeId": { get: { - controller: 'ChallengeController', - method: 'getChallenge', - scopes: [READ, ALL] + controller: "ChallengeController", + method: "getChallenge", + scopes: [READ, ALL], }, put: { - controller: 'ChallengeController', - method: 'fullyUpdateChallenge', - auth: 'jwt', - access: [constants.UserRoles.Admin, constants.UserRoles.SelfServiceCustomer, constants.UserRoles.Copilot, constants.UserRoles.Manager, constants.UserRoles.User], - scopes: [UPDATE, ALL] + controller: "ChallengeController", + method: "updateChallenge", + auth: "jwt", + access: [ + constants.UserRoles.Admin, + constants.UserRoles.SelfServiceCustomer, + constants.UserRoles.Copilot, + constants.UserRoles.Manager, + constants.UserRoles.User, + ], + scopes: [UPDATE, ALL], }, patch: { - controller: 'ChallengeController', - method: 'partiallyUpdateChallenge', - auth: 'jwt', - access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.SelfServiceCustomer, constants.UserRoles.Manager, constants.UserRoles.User], - scopes: [UPDATE, ALL] + controller: "ChallengeController", + method: "updateChallenge", + auth: "jwt", + access: [ + constants.UserRoles.Admin, + constants.UserRoles.SelfServiceCustomer, + constants.UserRoles.Copilot, + constants.UserRoles.Manager, + constants.UserRoles.User, + ], + scopes: [UPDATE, ALL], }, delete: { - controller: 'ChallengeController', - method: 'deleteChallenge', - auth: 'jwt', - access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.SelfServiceCustomer, constants.UserRoles.Manager, constants.UserRoles.User], - scopes: [DELETE, ALL] - } + controller: "ChallengeController", + method: "deleteChallenge", + auth: "jwt", + access: [ + constants.UserRoles.Admin, + constants.UserRoles.Copilot, + constants.UserRoles.SelfServiceCustomer, + constants.UserRoles.Manager, + constants.UserRoles.User, + ], + scopes: [DELETE, ALL], + }, }, - '/challenges/:challengeId/statistics': { + "/challenges/:challengeId/statistics": { get: { - controller: 'ChallengeController', - method: 'getChallengeStatistics' - } + controller: "ChallengeController", + method: "getChallengeStatistics", + }, }, - '/challenges/:challengeId/notifications': { + "/challenges/:challengeId/notifications": { post: { - controller: 'ChallengeController', - method: 'sendNotifications', - auth: 'jwt', + controller: "ChallengeController", + method: "sendNotifications", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot], - scopes: [CREATE, ALL] - } + scopes: [CREATE, ALL], + }, }, - '/challenge-types': { + "/challenge-types": { get: { - controller: 'ChallengeTypeController', - method: 'searchChallengeTypes' + controller: "ChallengeTypeController", + method: "searchChallengeTypes", }, post: { - controller: 'ChallengeTypeController', - method: 'createChallengeType', - auth: 'jwt', + controller: "ChallengeTypeController", + method: "createChallengeType", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [CREATE, ALL] - } + scopes: [CREATE, ALL], + }, }, - '/challenge-types/:challengeTypeId': { + "/challenge-types/:challengeTypeId": { get: { - controller: 'ChallengeTypeController', - method: 'getChallengeType' + controller: "ChallengeTypeController", + method: "getChallengeType", }, put: { - controller: 'ChallengeTypeController', - method: 'fullyUpdateChallengeType', - auth: 'jwt', + controller: "ChallengeTypeController", + method: "fullyUpdateChallengeType", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, patch: { - controller: 'ChallengeTypeController', - method: 'partiallyUpdateChallengeType', - auth: 'jwt', + controller: "ChallengeTypeController", + method: "partiallyUpdateChallengeType", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, delete: { - controller: 'ChallengeTypeController', - method: 'deleteChallengeType', - auth: 'jwt', + controller: "ChallengeTypeController", + method: "deleteChallengeType", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [DELETE, ALL] - } + scopes: [DELETE, ALL], + }, }, - '/challenge-tracks': { + "/challenge-tracks": { get: { - controller: 'ChallengeTrackController', - method: 'searchChallengeTracks' + controller: "ChallengeTrackController", + method: "searchChallengeTracks", }, post: { - controller: 'ChallengeTrackController', - method: 'createChallengeTrack', - auth: 'jwt', + controller: "ChallengeTrackController", + method: "createChallengeTrack", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [CREATE, ALL] - } + scopes: [CREATE, ALL], + }, }, - '/challenge-tracks/:challengeTrackId': { + "/challenge-tracks/:challengeTrackId": { get: { - controller: 'ChallengeTrackController', - method: 'getChallengeTrack' + controller: "ChallengeTrackController", + method: "getChallengeTrack", }, put: { - controller: 'ChallengeTrackController', - method: 'fullyUpdateChallengeTrack', - auth: 'jwt', + controller: "ChallengeTrackController", + method: "fullyUpdateChallengeTrack", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, patch: { - controller: 'ChallengeTrackController', - method: 'partiallyUpdateChallengeTrack', - auth: 'jwt', + controller: "ChallengeTrackController", + method: "partiallyUpdateChallengeTrack", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, delete: { - controller: 'ChallengeTrackController', - method: 'deleteChallengeTrack', - auth: 'jwt', + controller: "ChallengeTrackController", + method: "deleteChallengeTrack", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [DELETE, ALL] - } + scopes: [DELETE, ALL], + }, }, - '/challenge-timelines': { + "/challenge-timelines": { get: { - controller: 'ChallengeTimelineTemplateController', - method: 'searchChallengeTimelineTemplates' + controller: "ChallengeTimelineTemplateController", + method: "searchChallengeTimelineTemplates", // auth: 'jwt', // access: [constants.UserRoles.Admin, constants.UserRoles.Copilot], // scopes: [READ, ALL] }, post: { - controller: 'ChallengeTimelineTemplateController', - method: 'createChallengeTimelineTemplate', - auth: 'jwt', + controller: "ChallengeTimelineTemplateController", + method: "createChallengeTimelineTemplate", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [CREATE, ALL] - } + scopes: [CREATE, ALL], + }, }, - '/challenge-timelines/:challengeTimelineTemplateId': { + "/challenge-timelines/:challengeTimelineTemplateId": { get: { - controller: 'ChallengeTimelineTemplateController', - method: 'getChallengeTimelineTemplate' + controller: "ChallengeTimelineTemplateController", + method: "getChallengeTimelineTemplate", // auth: 'jwt', // access: [constants.UserRoles.Admin, constants.UserRoles.Copilot], // scopes: [READ, ALL] }, put: { - controller: 'ChallengeTimelineTemplateController', - method: 'fullyUpdateChallengeTimelineTemplate', - auth: 'jwt', + controller: "ChallengeTimelineTemplateController", + method: "fullyUpdateChallengeTimelineTemplate", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, delete: { - controller: 'ChallengeTimelineTemplateController', - method: 'deleteChallengeTimelineTemplate', - auth: 'jwt', + controller: "ChallengeTimelineTemplateController", + method: "deleteChallengeTimelineTemplate", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [DELETE, ALL] - } + scopes: [DELETE, ALL], + }, }, - '/challenge-audit-logs': { + "/challenge-audit-logs": { get: { - controller: 'AuditLogController', - method: 'searchAuditLogs', - auth: 'jwt', + controller: "AuditLogController", + method: "searchAuditLogs", + auth: "jwt", access: [constants.UserRoles.Admin], - scopes: [READ] - } + scopes: [READ], + }, }, - '/challenge-phases': { + "/challenge-phases": { get: { - controller: 'ChallengePhaseController', - method: 'searchPhases', - scopes: [READ, ALL] + controller: "ChallengePhaseController", + method: "searchPhases", + scopes: [READ, ALL], }, post: { - controller: 'ChallengePhaseController', - method: 'createPhase', - auth: 'jwt', + controller: "ChallengePhaseController", + method: "createPhase", + auth: "jwt", access: [constants.UserRoles.Admin], - scopes: [CREATE, ALL] - } + scopes: [CREATE, ALL], + }, }, - '/challenge-phases/:challengePhaseId': { + "/challenge-phases/:challengePhaseId": { get: { - controller: 'ChallengePhaseController', - method: 'getPhase', - auth: 'jwt', + controller: "ChallengePhaseController", + method: "getPhase", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [READ, ALL] + scopes: [READ, ALL], }, put: { - controller: 'ChallengePhaseController', - method: 'fullyUpdatePhase', - auth: 'jwt', + controller: "ChallengePhaseController", + method: "fullyUpdatePhase", + auth: "jwt", access: [constants.UserRoles.Admin], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, patch: { - controller: 'ChallengePhaseController', - method: 'partiallyUpdatePhase', - auth: 'jwt', + controller: "ChallengePhaseController", + method: "partiallyUpdatePhase", + auth: "jwt", access: [constants.UserRoles.Admin], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, delete: { - controller: 'ChallengePhaseController', - method: 'deletePhase', - auth: 'jwt', + controller: "ChallengePhaseController", + method: "deletePhase", + auth: "jwt", access: [constants.UserRoles.Admin], - scopes: [DELETE, ALL] - } + scopes: [DELETE, ALL], + }, }, - '/timeline-templates': { + "/timeline-templates": { get: { - controller: 'TimelineTemplateController', - method: 'searchTimelineTemplates', - scopes: [READ, ALL] + controller: "TimelineTemplateController", + method: "searchTimelineTemplates", + scopes: [READ, ALL], }, post: { - controller: 'TimelineTemplateController', - method: 'createTimelineTemplate', - auth: 'jwt', + controller: "TimelineTemplateController", + method: "createTimelineTemplate", + auth: "jwt", access: [constants.UserRoles.Admin], - scopes: [CREATE, ALL] - } + scopes: [CREATE, ALL], + }, }, - '/timeline-templates/:timelineTemplateId': { + "/timeline-templates/:timelineTemplateId": { get: { - controller: 'TimelineTemplateController', - method: 'getTimelineTemplate', - auth: 'jwt', + controller: "TimelineTemplateController", + method: "getTimelineTemplate", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [READ, ALL] + scopes: [READ, ALL], }, put: { - controller: 'TimelineTemplateController', - method: 'fullyUpdateTimelineTemplate', - auth: 'jwt', + controller: "TimelineTemplateController", + method: "fullyUpdateTimelineTemplate", + auth: "jwt", access: [constants.UserRoles.Admin], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, patch: { - controller: 'TimelineTemplateController', - method: 'partiallyUpdateTimelineTemplate', - auth: 'jwt', + controller: "TimelineTemplateController", + method: "partiallyUpdateTimelineTemplate", + auth: "jwt", access: [constants.UserRoles.Admin], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, delete: { - controller: 'TimelineTemplateController', - method: 'deleteTimelineTemplate', - auth: 'jwt', + controller: "TimelineTemplateController", + method: "deleteTimelineTemplate", + auth: "jwt", access: [constants.UserRoles.Admin], - scopes: [DELETE, ALL] - } + scopes: [DELETE, ALL], + }, }, - '/challenges/:challengeId/attachments': { + "/challenges/:challengeId/attachments": { post: { - controller: 'AttachmentController', - method: 'createAttachment', - auth: 'jwt', + controller: "AttachmentController", + method: "createAttachment", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [CREATE, ALL] - } + scopes: [CREATE, ALL], + }, }, - '/challenges/:challengeId/attachments/:attachmentId': { + "/challenges/:challengeId/attachments/:attachmentId": { get: { - controller: 'AttachmentController', - method: 'getAttachment', - auth: 'jwt', // any authenticated role is allowed - scopes: [READ, ALL] + controller: "AttachmentController", + method: "getAttachment", + auth: "jwt", // any authenticated role is allowed + scopes: [READ, ALL], }, put: { - controller: 'AttachmentController', - method: 'updateAttachment', - auth: 'jwt', + controller: "AttachmentController", + method: "updateAttachment", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, patch: { - controller: 'AttachmentController', - method: 'partiallyUpdateAttachment', - auth: 'jwt', + controller: "AttachmentController", + method: "partiallyUpdateAttachment", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [UPDATE, ALL] + scopes: [UPDATE, ALL], }, delete: { - controller: 'AttachmentController', - method: 'deleteAttachment', - auth: 'jwt', + controller: "AttachmentController", + method: "deleteAttachment", + auth: "jwt", access: [constants.UserRoles.Admin, constants.UserRoles.Copilot, constants.UserRoles.Manager], - scopes: [DELETE, ALL] - } + scopes: [DELETE, ALL], + }, }, - '/challenges/:challengeId/attachments/:attachmentId/download': { + "/challenges/:challengeId/attachments/:attachmentId/download": { get: { - controller: 'AttachmentController', - method: 'downloadAttachment', - auth: 'jwt', // any authenticated role is allowed - scopes: [READ, ALL] - } - } -} + controller: "AttachmentController", + method: "downloadAttachment", + auth: "jwt", // any authenticated role is allowed + scopes: [READ, ALL], + }, + }, +}; diff --git a/src/scripts/check-templates.js b/src/scripts/check-templates.js index fab103ca..1ba94d19 100644 --- a/src/scripts/check-templates.js +++ b/src/scripts/check-templates.js @@ -1,18 +1,24 @@ -const _ = require('lodash') -const axios = require('axios') -const TEMPLATE_ID = '2d0807fa-ece1-4328-a260-76f5f6b559e0' // RUX challenge +const _ = require("lodash"); +const axios = require("axios"); +const TEMPLATE_ID = "2d0807fa-ece1-4328-a260-76f5f6b559e0"; // RUX challenge // const TEMPLATE_ID = '7ebf1c69-f62f-4d3a-bdfb-fe9ddb56861c' // dev challenge // const TEMPLATE_ID = 'd4201ca4-8437-4d63-9957-3f7708184b07' // design with checkpoint -async function main () { - let res - res = await axios.get('http://api.topcoder-dev.com/v5/timeline-templates') - const template = _.find(res.data, entry => entry.id === TEMPLATE_ID) - res = await axios.get('http://api.topcoder-dev.com/v5/challenge-phases') - const phases = res.data +async function main() { + let res; + res = await axios.get("http://api.topcoder-dev.com/v5/timeline-templates"); + const template = _.find(res.data, (entry) => entry.id === TEMPLATE_ID); + res = await axios.get("http://api.topcoder-dev.com/v5/challenge-phases"); + const phases = res.data; _.each(template.phases, (phase) => { - const phaseInstance = _.find(phases, p => p.id === phase.phaseId) - const pred = phase.predecessor ? _.find(phases, p => p.id === phase.predecessor) : null - console.log(`Phase Length: ${phase.defaultDuration / 60 / 60} hrs \t ${phaseInstance.name} - Depends on ${pred ? pred.name : 'nothing'}`) - }) + const phaseInstance = _.find(phases, (p) => p.id === phase.phaseId); + const pred = phase.predecessor + ? _.find(phases, (p) => p.id === phase.predecessor) + : null; + console.log( + `Phase Length: ${phase.defaultDuration / 60 / 60} hrs \t ${ + phaseInstance.name + } - Depends on ${pred ? pred.name : "nothing"}` + ); + }); } -main() +main(); diff --git a/src/scripts/create-tables.js b/src/scripts/create-tables.js index 624e3f13..6496b4e6 100644 --- a/src/scripts/create-tables.js +++ b/src/scripts/create-tables.js @@ -2,29 +2,31 @@ * Create table schemes in database */ -const models = require('../models') -const { includes } = require('lodash') -const logger = require('../common/logger') +const models = require("../models"); +const { includes } = require("lodash"); +const logger = require("../common/logger"); -logger.info('Requesting to create tables...') +logger.info("Requesting to create tables..."); -const promises = [] -const skipModels = ['DynamoDB'] +const promises = []; +const skipModels = ["DynamoDB"]; -Object.keys(models).forEach(modelName => { +Object.keys(models).forEach((modelName) => { if (!includes(skipModels, modelName)) { - promises.push(models[modelName].$__.table.create()) + promises.push(models[modelName].$__.table.create()); } else { - logger.info(`Skipping ${modelName}`) + logger.info(`Skipping ${modelName}`); } -}) +}); Promise.all(promises) .then(() => { - logger.info('All tables have been requested to be created. Creating processes is run asynchronously') - process.exit() + logger.info( + "All tables have been requested to be created. Creating processes is run asynchronously" + ); + process.exit(); }) .catch((err) => { - logger.logFullError(err) - process.exit(1) - }) + logger.logFullError(err); + process.exit(1); + }); diff --git a/src/scripts/drop-tables.js b/src/scripts/drop-tables.js index ccab820b..412c864e 100644 --- a/src/scripts/drop-tables.js +++ b/src/scripts/drop-tables.js @@ -2,29 +2,31 @@ * Drop tables in database. All data will be cleared. */ -const models = require('../models') -const { includes } = require('lodash') -const logger = require('../common/logger') +const models = require("../models"); +const { includes } = require("lodash"); +const logger = require("../common/logger"); -logger.info('Requesting to delete tables...') +logger.info("Requesting to delete tables..."); -const promises = [] -const skipModels = ['DynamoDB'] +const promises = []; +const skipModels = ["DynamoDB"]; -Object.keys(models).forEach(modelName => { +Object.keys(models).forEach((modelName) => { if (!includes(skipModels, modelName)) { - promises.push(models[modelName].$__.table.delete()) + promises.push(models[modelName].$__.table.delete()); } else { - logger.info(`Skipping ${modelName}`) + logger.info(`Skipping ${modelName}`); } -}) +}); Promise.all(promises) .then(() => { - logger.info('All tables have been requested to be deleted. Deleting processes is run asynchronously') - process.exit() + logger.info( + "All tables have been requested to be deleted. Deleting processes is run asynchronously" + ); + process.exit(); }) .catch((err) => { - logger.logFullError(err) - process.exit(1) - }) + logger.logFullError(err); + process.exit(1); + }); diff --git a/src/scripts/seed-tables.js b/src/scripts/seed-tables.js index 415fa78b..c2fc00f9 100644 --- a/src/scripts/seed-tables.js +++ b/src/scripts/seed-tables.js @@ -2,35 +2,39 @@ * Insert seed data to tables in database */ -const { get, includes } = require('lodash') -const models = require('../models') -const logger = require('../common/logger') +const { get, includes } = require("lodash"); +const models = require("../models"); +const logger = require("../common/logger"); -logger.info('Requesting to insert seed data to the tables...') +logger.info("Requesting to insert seed data to the tables..."); -const promises = [] -const skipModels = [] +const promises = []; +const skipModels = []; -Object.keys(models).forEach(modelName => { +Object.keys(models).forEach((modelName) => { if (includes(skipModels, modelName)) { - logger.warn(`Skipping Seed Model ${modelName}`) - return + logger.warn(`Skipping Seed Model ${modelName}`); + return; } try { - const data = require(`./seed/${modelName}.json`) - logger.info(`Inserting ${get(data, 'length')} records in table ${modelName}`) - promises.push(models[modelName].batchPut(data)) + const data = require(`./seed/${modelName}.json`); + logger.info( + `Inserting ${get(data, "length")} records in table ${modelName}` + ); + promises.push(models[modelName].batchPut(data)); } catch (e) { - logger.warn(`No records will be inserted in table ${modelName}`) + logger.warn(`No records will be inserted in table ${modelName}`); } -}) +}); Promise.all(promises) .then(() => { - logger.info('All tables have been inserted with the data. The processes is run asynchronously') - process.exit() + logger.info( + "All tables have been inserted with the data. The processes is run asynchronously" + ); + process.exit(); }) .catch((err) => { - logger.logFullError(err) - process.exit(1) - }) + logger.logFullError(err); + process.exit(1); + }); diff --git a/src/scripts/sync-es.js b/src/scripts/sync-es.js index d6f5b8da..b5ba3388 100644 --- a/src/scripts/sync-es.js +++ b/src/scripts/sync-es.js @@ -2,33 +2,55 @@ * Migrate Data from Dynamo DB to ES */ -const config = require('config') -const logger = require('../common/logger') -const helper = require('../common/helper') +const config = require("config"); +const logger = require("../common/logger"); +const helper = require("../common/helper"); +const models = require("../models"); +const _ = require("lodash"); -const esClient = helper.getESClient() +const esClient = helper.getESClient(); + +async function indexChallenge(challenge) { + console.log("Indexing challenge", challenge.id); + try { + await esClient.update({ + index: config.get("ES.ES_INDEX"), + type: config.get("ES.OPENSEARCH") == "false" ? config.get("ES.ES_TYPE") : undefined, + id: challenge.id, + body: { doc: challenge, doc_as_upsert: true }, + }); + } catch (err) { + console.log("Error indexing challenge", challenge.id, err); + } +} /* * Migrate records from DB to ES */ -async function migrateRecords () { - const result = await helper.scan('Challenge') - for (const challenge of result) { - await esClient.update({ - index: config.get('ES.ES_INDEX'), - type: config.get('ES.ES_TYPE'), - id: challenge.id, - body: { doc: challenge, doc_as_upsert: true } - }) +async function migrateRecords() { + let results = await models["Challenge"].scan().exec(); + let lastKey = results.lastKey; + + for (const challenge of results) { + await indexChallenge(challenge); + } + + while (!_.isUndefined(results.lastKey)) { + const results = await models["Challenge"].scan().startAt(lastKey).exec(); + for (const challenge of results) { + await indexChallenge(challenge); + } + + lastKey = results.lastKey; } } migrateRecords() .then(() => { - logger.info('Done') - process.exit() + logger.info("Done"); + process.exit(); }) .catch((err) => { - logger.logFullError(err) - process.exit(1) - }) + logger.logFullError(err); + process.exit(1); + }); diff --git a/src/scripts/update-es-mappings.js b/src/scripts/update-es-mappings.js index d9151674..8b351907 100644 --- a/src/scripts/update-es-mappings.js +++ b/src/scripts/update-es-mappings.js @@ -1,68 +1,70 @@ -const config = require('config') -const logger = require('../common/logger') -const helper = require('../common/helper') +const config = require("config"); +const logger = require("../common/logger"); +const helper = require("../common/helper"); -const esClient = helper.getESClient() +const esClient = helper.getESClient(); -function sleep (ms) { +function sleep(ms) { return new Promise((resolve) => { - setTimeout(resolve, ms) - }) + setTimeout(resolve, ms); + }); } -function createIndex (indexName) { - const body = { mappings: {} } - body.mappings[config.get('ES.ES_TYPE')] = { +function createIndex(indexName) { + const body = { mappings: {} }; + body.mappings[config.get("ES.ES_TYPE")] = { properties: { - id: { type: 'keyword' }, + id: { type: "keyword" }, name: { - type: 'keyword', - normalizer: 'custom_sort_normalizer' + type: "keyword", + normalizer: "custom_sort_normalizer", }, prizeSets: { properties: { - type: { type: 'text' }, + type: { type: "text" }, prizes: { properties: { - type: { type: 'text' }, - value: { type: 'float' } - } - } - } - } + type: { type: "text" }, + value: { type: "float" }, + }, + }, + }, + }, }, - dynamic_templates: [{ - metadata: { - path_match: 'metadata.*', - mapping: { - type: 'text' - } - } - }] - } + dynamic_templates: [ + { + metadata: { + path_match: "metadata.*", + mapping: { + type: "text", + }, + }, + }, + ], + }; body.settings = { analysis: { normalizer: { custom_sort_normalizer: { - type: 'custom', + type: "custom", char_filter: [], - filter: ['lowercase', 'asciifolding'] - } - } - } - } + filter: ["lowercase", "asciifolding"], + }, + }, + }, + }; return esClient.indices.create({ index: indexName, - body - }) + body, + }); } -async function updateMappings () { - const tempReindexing = config.get('ES.TEMP_REINDEXING') - let indexName = config.get('ES.ES_INDEX') - let backupIndex = 'challenge_tmp_dont_use_for_querying_backup' - let newIndexName = 'challenge_tmp_dont_use_for_querying' +async function updateMappings() { + const tempReindexing = config.get("ES.TEMP_REINDEXING"); + let indexName = config.get("ES.ES_INDEX"); + let backupIndex = "challenge_tmp_dont_use_for_querying_backup"; + let newIndexName = "challenge_tmp_dont_use_for_querying"; // if (tempReindexing) { // try { @@ -132,10 +134,10 @@ async function updateMappings () { updateMappings() .then(() => { - logger.info('Done') - process.exit() + logger.info("Done"); + process.exit(); }) .catch((err) => { - logger.logFullError(err) - process.exit(1) - }) + logger.logFullError(err); + process.exit(1); + }); diff --git a/src/scripts/view-data.js b/src/scripts/view-data.js index 8208005f..bcc1b465 100644 --- a/src/scripts/view-data.js +++ b/src/scripts/view-data.js @@ -2,33 +2,39 @@ * View table data. */ -require('../../app-bootstrap') -const _ = require('lodash') -const models = require('../models') -const logger = require('../common/logger') -const helper = require('../common/helper') +require("../../app-bootstrap"); +const _ = require("lodash"); +const models = require("../models"); +const logger = require("../common/logger"); +const helper = require("../common/helper"); const viewData = async (modelName) => { - const fieldNames = _.keys(models[modelName].$__.table.schema.attributes) - const records = await helper.scan(modelName) - console.log(_.map(records, e => _.pick(e, fieldNames))) -} + const fieldNames = _.keys(models[modelName].$__.table.schema.attributes); + const records = await helper.scan(modelName); + console.log(_.map(records, (e) => _.pick(e, fieldNames))); +}; if (process.argv.length === 2) { - logger.info(`Please provide one of the following table name: [${_.keys(models)}]`) - process.exit(1) + logger.info( + `Please provide one of the following table name: [${_.keys(models)}]` + ); + process.exit(1); } else { - const modelName = process.argv[2] + const modelName = process.argv[2]; if (_.keys(models).includes(modelName)) { - viewData(modelName).then(() => { - logger.info('Done!') - process.exit() - }).catch((e) => { - logger.logFullError(e) - process.exit(1) - }) + viewData(modelName) + .then(() => { + logger.info("Done!"); + process.exit(); + }) + .catch((e) => { + logger.logFullError(e); + process.exit(1); + }); } else { - logger.info(`Please provide one of the following table name: [${_.keys(models)}]`) - process.exit(1) + logger.info( + `Please provide one of the following table name: [${_.keys(models)}]` + ); + process.exit(1); } } diff --git a/src/scripts/view-es-data.js b/src/scripts/view-es-data.js index aebce8c5..aa06115b 100644 --- a/src/scripts/view-es-data.js +++ b/src/scripts/view-es-data.js @@ -2,30 +2,27 @@ * View all ES data. */ -const helper = require('../common/helper') -const config = require('config') -const logger = require('../common/logger') +const helper = require("../common/helper"); +const config = require("config"); +const logger = require("../common/logger"); -const esClient = helper.getESClient() +const esClient = helper.getESClient(); -async function showESData () { +async function showESData() { const result = await esClient.search({ - index: config.get('ES.ES_INDEX'), - type: config.get('ES.ES_TYPE') - }) - return result + index: config.get("ES.ES_INDEX"), + }); + return result; } showESData() - .then(result => { - logger.info('All data in ES is shown belows.') - console.log( - JSON.stringify(result.hits.hits, null, 2) - ) - logger.info('Done!') - process.exit() - }) - .catch(err => { - console.log(err) - process.exit(1) + .then((result) => { + logger.info("All data in ES is shown belows."); + console.log(JSON.stringify(result.hits.hits, null, 2)); + logger.info("Done!"); + process.exit(); }) + .catch((err) => { + console.log(err); + process.exit(1); + }); diff --git a/src/services/AttachmentService.js b/src/services/AttachmentService.js index f9e30a81..8c4d6fb3 100644 --- a/src/services/AttachmentService.js +++ b/src/services/AttachmentService.js @@ -1,21 +1,33 @@ - /** * This service provides operations of attachments. */ +const { GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT } = process.env; + +const { + DomainHelper: { getLookupCriteria, getScanCriteria }, +} = require("@topcoder-framework/lib-common"); + +const { AttachmentDomain, ChallengeDomain } = require("@topcoder-framework/domain-challenge"); -const _ = require('lodash') -const Joi = require('joi') -const uuid = require('uuid/v4') -const config = require('config') -const errors = require('../common/errors') -const helper = require('../common/helper') -const s3ParseUrl = require('../common/s3ParseUrl') -const models = require('../models') -const logger = require('../common/logger') -const constants = require('../../app-constants') -const challengeService = require('./ChallengeService') +const _ = require("lodash"); +const Joi = require("joi"); +const config = require("config"); +const errors = require("../common/errors"); +const helper = require("../common/helper"); +const s3ParseUrl = require("../common/s3ParseUrl"); +const logger = require("../common/logger"); +const constants = require("../../app-constants"); +const challengeService = require("./ChallengeService"); -const bucketWhitelist = config.AMAZON.BUCKET_WHITELIST.split(',').map((bucketName) => bucketName.trim()) +const bucketWhitelist = config.AMAZON.BUCKET_WHITELIST.split(",").map((bucketName) => + bucketName.trim() +); + +const attachmentDomain = new AttachmentDomain( + GRPC_CHALLENGE_SERVER_HOST, + GRPC_CHALLENGE_SERVER_PORT +); +const challengeDomain = new ChallengeDomain(GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT); /** * Check if a url is acceptable. @@ -23,15 +35,15 @@ const bucketWhitelist = config.AMAZON.BUCKET_WHITELIST.split(',').map((bucketNam * @param {String} url the url * @returns {undefined} */ -function validateUrl (url) { - const s3UrlObject = s3ParseUrl(url) +function validateUrl(url) { + const s3UrlObject = s3ParseUrl(url); if (!s3UrlObject) { - return + return; } if (bucketWhitelist.includes(s3UrlObject.bucket)) { - return + return; } - throw new errors.BadRequestError(`The bucket ${s3UrlObject.bucket} is not in the whitelist`) + throw new errors.BadRequestError(`The bucket ${s3UrlObject.bucket} is not in the whitelist`); } /** @@ -40,13 +52,13 @@ function validateUrl (url) { * @param {String} attachmentId the attachment id * @returns {Object} the challenge and the attachment */ -async function _getChallengeAttachment (challengeId, attachmentId) { - const challenge = await helper.getById('Challenge', challengeId) - const attachment = await models.Attachment.get(attachmentId) +async function _getChallengeAttachment(challengeId, attachmentId) { + const challenge = await helperchallengeDomain.lookup(getLookupCriteria("id", challengeId)); + const attachment = await attachmentDomain.lookup(getLookupCriteria("id", attachmentId)); if (!attachment || attachment.challengeId !== challengeId) { - throw errors.NotFoundError(`Attachment ${attachmentId} not found in challenge ${challengeId}`) + throw errors.NotFoundError(`Attachment ${attachmentId} not found in challenge ${challengeId}`); } - return { challenge, attachment } + return { challenge, attachment }; } /** @@ -55,38 +67,40 @@ async function _getChallengeAttachment (challengeId, attachmentId) { * @param {Array} attachments the attachments to be created * @returns {Object} the created attachment */ -async function createAttachment (currentUser, challengeId, attachments) { - const challenge = await helper.getById('Challenge', challengeId) - await helper.ensureUserCanModifyChallenge(currentUser, challenge) - const newAttachments = [] +async function createAttachment(currentUser, challengeId, attachments) { + const challenge = await helperchallengeDomain.lookup(getLookupCriteria("id", challengeId)); + await helper.ensureUserCanModifyChallenge(currentUser, challenge); + const newAttachments = []; for (const attachment of attachments) { - validateUrl(attachment.url) - const attachmentObject = { id: uuid(), challengeId, ...attachment } - const newAttachment = await helper.create('Attachment', attachmentObject) - await helper.postBusEvent(constants.Topics.ChallengeAttachmentCreated, newAttachment) - newAttachments.push(newAttachment) + validateUrl(attachment.url); + const attachmentObject = { challengeId, ...attachment }; + const newAttachment = await attachmentDomain.create(attachmentObject); + await helper.postBusEvent(constants.Topics.ChallengeAttachmentCreated, newAttachment); + newAttachments.push(newAttachment); } // update challenge object await challengeService.partiallyUpdateChallenge(currentUser, challengeId, { - attachments: [ - ..._.get(challenge, 'attachments', []), - ...newAttachments - ] - }) + attachments: [..._.get(challenge, "attachments", []), ...newAttachments], + }); // post bus event - return newAttachments + return newAttachments; } createAttachment.schema = { currentUser: Joi.any(), challengeId: Joi.id(), - attachments: Joi.array().items(Joi.object().keys({ - name: Joi.string().required(), - url: Joi.string().uri().required(), - fileSize: Joi.fileSize(), - description: Joi.string() - })).required().min(1) -} + attachments: Joi.array() + .items( + Joi.object().keys({ + name: Joi.string().required(), + url: Joi.string().uri().required(), + fileSize: Joi.fileSize(), + description: Joi.string(), + }) + ) + .required() + .min(1), +}; /** * Get attachment @@ -94,17 +108,17 @@ createAttachment.schema = { * @param {String} attachmentId the attachment id * @returns {Object} the attachment with given id */ -async function getAttachment (currentUser, challengeId, attachmentId) { - const { challenge, attachment } = await _getChallengeAttachment(challengeId, attachmentId) - await helper.ensureUserCanViewChallenge(currentUser, challenge) - return attachment +async function getAttachment(currentUser, challengeId, attachmentId) { + const { challenge, attachment } = await _getChallengeAttachment(challengeId, attachmentId); + await helper.ensureUserCanViewChallenge(currentUser, challenge); + return attachment; } getAttachment.schema = { currentUser: Joi.any(), challengeId: Joi.id(), - attachmentId: Joi.id() -} + attachmentId: Joi.id(), +}; /** * Update attachment. @@ -114,32 +128,37 @@ getAttachment.schema = { * @param {Boolean} isFull the flag indicate it is a fully update operation. * @returns {Object} the updated attachment */ -async function update (currentUser, challengeId, attachmentId, data, isFull) { - const { challenge, attachment } = await _getChallengeAttachment(challengeId, attachmentId) - await helper.ensureUserCanModifyChallenge(currentUser, challenge) - validateUrl(data.url) +async function update(currentUser, challengeId, attachmentId, data, isFull) { + const { challenge, attachment } = await _getChallengeAttachment(challengeId, attachmentId); + await helper.ensureUserCanModifyChallenge(currentUser, challenge); + validateUrl(data.url); if (isFull) { // optional fields can be undefined - attachment.fileSize = data.fileSize - attachment.description = data.description + attachment.fileSize = data.fileSize; + attachment.description = data.description; } - const ret = await helper.update(attachment, data) + const { items } = await attachmentDomain.update({ + filterCriteria: getScanCriteria({ id: attachmentId }), + updateInput: data, + }); // update challenge object - const newAttachments = _.get(challenge, 'attachments', []) + const newAttachments = _.get(challenge, "attachments", []); try { - newAttachments[_.findIndex(newAttachments, a => a.id === attachmentId)] = ret + newAttachments[_.findIndex(newAttachments, (a) => a.id === attachmentId)] = items[0]; await challengeService.partiallyUpdateChallenge(currentUser, challengeId, { - attachments: newAttachments - }) + attachments: newAttachments, + }); } catch (e) { - logger.warn(`The attachment ${attachmentId} does not exist on the challenge object`) + logger.warn(`The attachment ${attachmentId} does not exist on the challenge object`); } // post bus event - await helper.postBusEvent(constants.Topics.ChallengeAttachmentUpdated, - isFull ? ret : _.assignIn({ id: attachmentId }, data)) - return ret + await helper.postBusEvent( + constants.Topics.ChallengeAttachmentUpdated, + isFull ? items[0] : _.assignIn({ id: attachmentId }, data) + ); + return items[0]; } /** @@ -149,21 +168,23 @@ async function update (currentUser, challengeId, attachmentId, data, isFull) { * @param {Object} data the attachment data to be updated * @returns {Object} the updated attachment */ -async function fullyUpdateAttachment (currentUser, challengeId, attachmentId, data) { - return update(currentUser, challengeId, attachmentId, data, true) +async function fullyUpdateAttachment(currentUser, challengeId, attachmentId, data) { + return update(currentUser, challengeId, attachmentId, data, true); } fullyUpdateAttachment.schema = { currentUser: Joi.any(), challengeId: Joi.id(), attachmentId: Joi.id(), - data: Joi.object().keys({ - name: Joi.string().required(), - url: Joi.string().uri().required(), - fileSize: Joi.fileSize(), - description: Joi.string() - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string().required(), + url: Joi.string().uri().required(), + fileSize: Joi.fileSize(), + description: Joi.string(), + }) + .required(), +}; /** * Partially update attachment. @@ -172,55 +193,62 @@ fullyUpdateAttachment.schema = { * @param {Object} data the attachment data to be updated * @returns {Object} the updated attachment */ -async function partiallyUpdateAttachment (currentUser, challengeId, attachmentId, data) { - return update(currentUser, challengeId, attachmentId, data) +async function partiallyUpdateAttachment(currentUser, challengeId, attachmentId, data) { + return update(currentUser, challengeId, attachmentId, data); } partiallyUpdateAttachment.schema = { currentUser: Joi.any(), challengeId: Joi.id(), attachmentId: Joi.id(), - data: Joi.object().keys({ - name: Joi.string(), - url: Joi.string().uri(), - fileSize: Joi.fileSize(), - description: Joi.string() - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string(), + url: Joi.string().uri(), + fileSize: Joi.fileSize(), + description: Joi.string(), + }) + .required(), +}; /** * Delete attachment. * @param {String} attachmentId the attachment id * @returns {Object} the deleted attachment */ -async function deleteAttachment (currentUser, challengeId, attachmentId) { - const { challenge, attachment } = await _getChallengeAttachment(challengeId, attachmentId) - await helper.ensureUserCanModifyChallenge(currentUser, challenge) - const s3UrlObject = s3ParseUrl(attachment.url) +async function deleteAttachment(currentUser, challengeId, attachmentId) { + const { challenge, attachment } = await _getChallengeAttachment(challengeId, attachmentId); + await helper.ensureUserCanModifyChallenge(currentUser, challenge); + const s3UrlObject = s3ParseUrl(attachment.url); if (s3UrlObject) { - await helper.deleteFromS3(s3UrlObject.bucket, s3UrlObject.key) + await helper.deleteFromS3(s3UrlObject.bucket, s3UrlObject.key); } - await attachment.delete() + + await attachmentDomain.delete(getLookupCriteria("id", attachmentId)); + // update challenge object - const newAttachments = _.get(challenge, 'attachments', []) + const newAttachments = _.get(challenge, "attachments", []); try { - newAttachments.splice(_.findIndex(newAttachments, a => a.id === attachmentId), 1) + newAttachments.splice( + _.findIndex(newAttachments, (a) => a.id === attachmentId), + 1 + ); await challengeService.partiallyUpdateChallenge(currentUser, challengeId, { - attachments: newAttachments - }) + attachments: newAttachments, + }); } catch (e) { - logger.warn(`The attachment ${attachmentId} does not exist on the challenge object`) + logger.warn(`The attachment ${attachmentId} does not exist on the challenge object`); } // post bus event - await helper.postBusEvent(constants.Topics.ChallengeAttachmentDeleted, attachment) - return attachment + await helper.postBusEvent(constants.Topics.ChallengeAttachmentDeleted, attachment); + return attachment; } deleteAttachment.schema = { currentUser: Joi.any(), challengeId: Joi.id(), - attachmentId: Joi.id() -} + attachmentId: Joi.id(), +}; /** * Download attachment. @@ -228,26 +256,26 @@ deleteAttachment.schema = { * @param {String} attachmentId the attachment id * @returns {Promise} the downloaded attachment data */ -async function downloadAttachment (currentUser, challengeId, attachmentId) { - const { challenge, attachment } = await _getChallengeAttachment(challengeId, attachmentId) - await helper.ensureUserCanViewChallenge(currentUser, challenge) - const s3UrlObject = s3ParseUrl(attachment.url) +async function downloadAttachment(currentUser, challengeId, attachmentId) { + const { challenge, attachment } = await _getChallengeAttachment(challengeId, attachmentId); + await helper.ensureUserCanViewChallenge(currentUser, challenge); + const s3UrlObject = s3ParseUrl(attachment.url); if (s3UrlObject) { // download from S3 - const data = await helper.downloadFromS3(s3UrlObject.bucket, s3UrlObject.key) - data.fileName = attachment.name - return data + const data = await helper.downloadFromS3(s3UrlObject.bucket, s3UrlObject.key); + data.fileName = attachment.name; + return data; } - const data = await helper.downloadFromFileStack(attachment.url) - data.fileName = attachment.name - return data + const data = await helper.downloadFromFileStack(attachment.url); + data.fileName = attachment.name; + return data; } downloadAttachment.schema = { currentUser: Joi.any(), challengeId: Joi.id(), - attachmentId: Joi.id() -} + attachmentId: Joi.id(), +}; module.exports = { createAttachment, @@ -255,7 +283,7 @@ module.exports = { fullyUpdateAttachment, partiallyUpdateAttachment, deleteAttachment, - downloadAttachment -} + downloadAttachment, +}; -logger.buildService(module.exports) +logger.buildService(module.exports); diff --git a/src/services/AuditLogService.js b/src/services/AuditLogService.js index a94e7b64..ee772c42 100644 --- a/src/services/AuditLogService.js +++ b/src/services/AuditLogService.js @@ -2,9 +2,9 @@ * This service provides operations of audit logs. */ -const _ = require('lodash') -const Joi = require('joi') -const helper = require('../common/helper') +const _ = require("lodash"); +const Joi = require("joi"); +const helper = require("../common/helper"); // const logger = require('../common/logger') /** @@ -12,21 +12,29 @@ const helper = require('../common/helper') * @param {Object} criteria the search criteria * @returns {Object} the search result */ -async function searchAuditLogs (criteria) { - const page = criteria.page || 1 - const perPage = criteria.perPage || 50 - let records = await helper.scanAll('AuditLog') +async function searchAuditLogs(criteria) { + const page = criteria.page || 1; + const perPage = criteria.perPage || 50; + let records = await helper.scanAll("AuditLog"); // TODO this needs to be in ES - if (criteria.fieldName) records = _.filter(records, e => helper.partialMatch(criteria.fieldName, e.fieldName)) - if (criteria.createdDateStart) records = _.filter(records, e => criteria.createdDateStart.getTime() <= e.created.getTime()) - if (criteria.createdDateEnd) records = _.filter(records, e => criteria.createdDateEnd.getTime() <= e.created.getTime()) - if (criteria.challengeId) records = _.filter(records, e => criteria.challengeId === e.challengeId) - if (criteria.createdBy) records = _.filter(records, e => criteria.createdBy.toLowerCase() === e.createdBy.toLowerCase()) + if (criteria.fieldName) + records = _.filter(records, (e) => helper.partialMatch(criteria.fieldName, e.fieldName)); + if (criteria.createdDateStart) + records = _.filter(records, (e) => criteria.createdDateStart.getTime() <= e.created.getTime()); + if (criteria.createdDateEnd) + records = _.filter(records, (e) => criteria.createdDateEnd.getTime() <= e.created.getTime()); + if (criteria.challengeId) + records = _.filter(records, (e) => criteria.challengeId === e.challengeId); + if (criteria.createdBy) + records = _.filter( + records, + (e) => criteria.createdBy.toLowerCase() === e.createdBy.toLowerCase() + ); - const total = records.length - const result = records.slice((page - 1) * perPage, page * perPage) + const total = records.length; + const result = records.slice((page - 1) * perPage, page * perPage); - return { total, page, perPage, result } + return { total, page, perPage, result }; } searchAuditLogs.schema = { @@ -37,12 +45,12 @@ searchAuditLogs.schema = { fieldName: Joi.string(), createdDateStart: Joi.date(), createdDateEnd: Joi.date(), - createdBy: Joi.string() - }) -} + createdBy: Joi.string(), + }), +}; module.exports = { - searchAuditLogs -} + searchAuditLogs, +}; -// logger.buildService(module.exports) +// logger.buildService(module.exports); diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index 64c0852a..1ebf81ed 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -2,26 +2,50 @@ * This service provides operations of challenge. */ -const _ = require('lodash') -const Joi = require('joi') -const uuid = require('uuid/v4') -const config = require('config') -const xss = require('xss') -const helper = require('../common/helper') -const logger = require('../common/logger') -const errors = require('../common/errors') -const phaseHelper = require('../common/phase-helper') -const constants = require('../../app-constants') -const models = require('../models') -const HttpStatus = require('http-status-codes') -const moment = require('moment') -const PhaseService = require('./PhaseService') -const ChallengeTypeService = require('./ChallengeTypeService') -const ChallengeTrackService = require('./ChallengeTrackService') -const ChallengeTimelineTemplateService = require('./ChallengeTimelineTemplateService') -const { BadRequestError } = require('../common/errors') - -const esClient = helper.getESClient() +const { GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT } = process.env; + +const { + DomainHelper: { getLookupCriteria, getScanCriteria }, +} = require("@topcoder-framework/lib-common"); + +const _ = require("lodash"); +const Joi = require("joi"); +const uuid = require("uuid/v4"); +const config = require("config"); +const xss = require("xss"); +const helper = require("../common/helper"); +const logger = require("../common/logger"); +const errors = require("../common/errors"); +const constants = require("../../app-constants"); +const HttpStatus = require("http-status-codes"); +const moment = require("moment"); +const PhaseService = require("./PhaseService"); +const ChallengeTypeService = require("./ChallengeTypeService"); +const ChallengeTrackService = require("./ChallengeTrackService"); +const ChallengeTimelineTemplateService = require("./ChallengeTimelineTemplateService"); +const TimelineTemplateService = require("./TimelineTemplateService"); +const { BadRequestError } = require("../common/errors"); + +const phaseHelper = require("../common/phase-helper"); +const projectHelper = require("../common/project-helper"); +const challengeHelper = require("../common/challenge-helper"); + +const { Metadata: GrpcMetadata } = require("@grpc/grpc-js"); + +const esClient = helper.getESClient(); + +const { ChallengeDomain, UpdateChallengeInput } = require("@topcoder-framework/domain-challenge"); +const { hasAdminRole } = require("../common/role-helper"); +const { + validateChallengeUpdateRequest, + enrichChallengeForResponse, + sanitizeRepeatedFieldsInUpdateRequest, + convertPrizeSetValuesToCents, + convertPrizeSetValuesToDollars, +} = require("../common/challenge-helper"); +const deepEqual = require("deep-equal"); + +const challengeDomain = new ChallengeDomain(GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT); /** * Check if user can perform modification/deletion to a challenge @@ -30,10 +54,17 @@ const esClient = helper.getESClient() * @param {Object} challenge the challenge object * @returns {undefined} */ -async function ensureAccessibleForChallenge (user, challenge) { - const userHasFullAccess = await helper.userHasFullAccess(challenge.id, user.userId) - if (!user.isMachine && !helper.hasAdminRole(user) && challenge.createdBy.toLowerCase() !== user.handle.toLowerCase() && !userHasFullAccess) { - throw new errors.ForbiddenError(`Only M2M, admin, challenge's copilot or users with full access can perform modification.`) +async function ensureAccessibleForChallenge(user, challenge) { + const userHasFullAccess = await helper.userHasFullAccess(challenge.id, user.userId); + if ( + !user.isMachine && + !hasAdminRole(user) && + challenge.createdBy.toLowerCase() !== user.handle.toLowerCase() && + !userHasFullAccess + ) { + throw new errors.ForbiddenError( + `Only M2M, admin, challenge's copilot or users with full access can perform modification.` + ); } } @@ -43,43 +74,50 @@ async function ensureAccessibleForChallenge (user, challenge) { * @param {Array} challenges the challenges to filter * @returns {Array} the challenges that can be accessed by current user */ -async function filterChallengesByGroupsAccess (currentUser, challenges) { - const res = [] - let userGroups - const needToCheckForGroupAccess = !currentUser ? true : !currentUser.isMachine && !helper.hasAdminRole(currentUser) - const subGroupsMap = {} +async function filterChallengesByGroupsAccess(currentUser, challenges) { + const res = []; + let userGroups; + const needToCheckForGroupAccess = !currentUser + ? true + : !currentUser.isMachine && !hasAdminRole(currentUser); + const subGroupsMap = {}; for (const challenge of challenges) { - challenge.groups = _.filter(challenge.groups, g => !_.includes(['null', 'undefined'], _.toString(g).toLowerCase())) - let expandedGroups = [] - if (!challenge.groups || _.get(challenge, 'groups.length', 0) === 0 || !needToCheckForGroupAccess) { - res.push(challenge) + challenge.groups = _.filter( + challenge.groups, + (g) => !_.includes(["null", "undefined"], _.toString(g).toLowerCase()) + ); + let expandedGroups = []; + if ( + !challenge.groups || + _.get(challenge, "groups.length", 0) === 0 || + !needToCheckForGroupAccess + ) { + res.push(challenge); } else if (currentUser) { // get user groups if not yet if (_.isNil(userGroups)) { - userGroups = await helper.getUserGroups(currentUser.userId) + userGroups = await helper.getUserGroups(currentUser.userId); } // Expand challenge groups by subGroups // results are being saved on a hashmap for efficiency for (const group of challenge.groups) { - let subGroups + let subGroups; if (subGroupsMap[group]) { - subGroups = subGroupsMap[group] + subGroups = subGroupsMap[group]; } else { - subGroups = await helper.expandWithSubGroups(group) - subGroupsMap[group] = subGroups + subGroups = await helper.expandWithSubGroups(group); + subGroupsMap[group] = subGroups; } - expandedGroups = [ - ..._.concat(expandedGroups, subGroups) - ] + expandedGroups = [..._.concat(expandedGroups, subGroups)]; } // check if there is matched group // logger.debug('Groups', challenge.groups, userGroups) if (_.find(expandedGroups, (group) => !!_.find(userGroups, (ug) => ug.id === group))) { - res.push(challenge) + res.push(challenge); } } } - return res + return res; } /** @@ -87,34 +125,14 @@ async function filterChallengesByGroupsAccess (currentUser, challenges) { * @param {Object} currentUser the user who perform operation * @param {Object} challenge the challenge to check */ -async function ensureAccessibleByGroupsAccess (currentUser, challenge) { - const filtered = await filterChallengesByGroupsAccess(currentUser, [challenge]) +async function ensureAccessibleByGroupsAccess(currentUser, challenge) { + const filtered = await filterChallengesByGroupsAccess(currentUser, [challenge]); if (filtered.length === 0) { throw new errors.ForbiddenError(`ensureAccessibleByGroupsAccess :: You don't have access to this group! Current User: ${JSON.stringify(currentUser)} Challenge: ${JSON.stringify(challenge)} Filtered: ${JSON.stringify(filtered)} - `) - } -} - -/** - * Ensure the user can access the groups being updated to - * @param {Object} currentUser the user who perform operation - * @param {Object} data the challenge data to be updated - * @param {String} challenge the original challenge data - */ -async function ensureAcessibilityToModifiedGroups (currentUser, data, challenge) { - const needToCheckForGroupAccess = !currentUser ? true : !currentUser.isMachine && !helper.hasAdminRole(currentUser) - if (!needToCheckForGroupAccess) { - return - } - const userGroups = await helper.getUserGroups(currentUser.userId) - const userGroupsIds = _.map(userGroups, group => group.id) - const updatedGroups = _.difference(_.union(challenge.groups, data.groups), _.intersection(challenge.groups, data.groups)) - const filtered = updatedGroups.filter(g => !userGroupsIds.includes(g)) - if (filtered.length > 0) { - throw new errors.ForbiddenError("ensureAcessibilityToModifiedGroups :: You don't have access to this group!") + `); } } @@ -126,42 +144,44 @@ async function ensureAcessibilityToModifiedGroups (currentUser, data, challenge) * @param {Number} perPage the perPage * @returns {Array} the search result */ -async function searchByLegacyId (currentUser, legacyId, page, perPage) { +async function searchByLegacyId(currentUser, legacyId, page, perPage) { const esQuery = { - index: config.get('ES.ES_INDEX'), - type: config.get('ES.ES_TYPE'), + index: config.get("ES.ES_INDEX"), + type: config.get("ES.OPENSEARCH") == "false" ? config.get("ES.ES_TYPE") : undefined, size: perPage, from: (page - 1) * perPage, body: { query: { term: { - legacyId - } - } - } - } - - logger.debug(`es Query ${JSON.stringify(esQuery)}`) - let docs + legacyId, + }, + }, + }, + }; + logger.debug(`es Query ${JSON.stringify(esQuery)}`); + let docs; try { - docs = await esClient.search(esQuery) + docs = + config.get("ES.OPENSEARCH") == "false" + ? await esClient.search(esQuery) + : (await esClient.search(esQuery)).body; } catch (e) { - logger.error(`Query Error from ES ${JSON.stringify(e)}`) + logger.error(`Query Error from ES ${JSON.stringify(e)}`); docs = { hits: { - hits: [] - } - } + hits: [], + }, + }; } - const ids = _.map(docs.hits.hits, item => item._source.id) - const result = [] + const ids = _.map(docs.hits.hits, (item) => item._source.id); + const result = []; for (const id of ids) { try { - const challenge = await getChallenge(currentUser, id) - result.push(challenge) + const challenge = await getChallenge(currentUser, id); + result.push(challenge); } catch (e) {} } - return result + return result; } /** @@ -170,312 +190,362 @@ async function searchByLegacyId (currentUser, legacyId, page, perPage) { * @param {Object} criteria the search criteria * @returns {Object} the search result */ -async function searchChallenges (currentUser, criteria) { +async function searchChallenges(currentUser, criteria) { // construct ES query - const page = criteria.page || 1 - const perPage = criteria.perPage || 20 + const page = criteria.page || 1; + const perPage = criteria.perPage || 20; if (!_.isUndefined(criteria.legacyId)) { - const result = await searchByLegacyId(currentUser, criteria.legacyId, page, perPage) - return { total: result.length, page, perPage, result } + const result = await searchByLegacyId(currentUser, criteria.legacyId, page, perPage); + return { total: result.length, page, perPage, result }; } - const boolQuery = [] - let sortByScore = false + const boolQuery = []; + let sortByScore = false; const matchPhraseKeys = [ - 'id', - 'timelineTemplateId', - 'projectId', - 'legacyId', - 'status', - 'createdBy', - 'updatedBy' - ] + "id", + "timelineTemplateId", + "projectId", + "legacyId", + "status", + "createdBy", + "updatedBy", + ]; - const hasAdminRole = helper.hasAdminRole(currentUser) + const _hasAdminRole = hasAdminRole(currentUser); - const includeSelfService = currentUser && (currentUser.isMachine || hasAdminRole || _.includes(config.SELF_SERVICE_WHITELIST_HANDLES, currentUser.handle.toLowerCase())) + const includeSelfService = + currentUser && + (currentUser.isMachine || + _hasAdminRole || + _.includes(config.SELF_SERVICE_WHITELIST_HANDLES, currentUser.handle.toLowerCase())); - const includedTrackIds = _.isArray(criteria.trackIds) ? criteria.trackIds : [] + const includedTrackIds = _.isArray(criteria.trackIds) ? criteria.trackIds : []; - const includedTypeIds = _.isArray(criteria.typeIds) ? criteria.typeIds : [] + const includedTypeIds = _.isArray(criteria.typeIds) ? criteria.typeIds : []; if (criteria.type) { - const typeSearchRes = await ChallengeTypeService.searchChallengeTypes({ abbreviation: criteria.type }) + const typeSearchRes = await ChallengeTypeService.searchChallengeTypes({ + abbreviation: criteria.type, + }); if (typeSearchRes.total > 0) { - criteria.typeId = _.get(typeSearchRes, 'result[0].id') + criteria.typeId = _.get(typeSearchRes, "result[0].id"); } } if (criteria.track) { - const trackSearchRes = await ChallengeTrackService.searchChallengeTracks({ abbreviation: criteria.track }) + const trackSearchRes = await ChallengeTrackService.searchChallengeTracks({ + abbreviation: criteria.track, + }); if (trackSearchRes.total > 0) { - criteria.trackId = _.get(trackSearchRes, 'result[0].id') + criteria.trackId = _.get(trackSearchRes, "result[0].id"); } } if (criteria.types) { for (const t of criteria.types) { - const typeSearchRes = await ChallengeTypeService.searchChallengeTypes({ abbreviation: t }) + const typeSearchRes = await ChallengeTypeService.searchChallengeTypes({ abbreviation: t }); if (typeSearchRes.total > 0 || criteria.types.length === 1) { - includedTypeIds.push(_.get(typeSearchRes, 'result[0].id')) + includedTypeIds.push(_.get(typeSearchRes, "result[0].id")); } } } if (criteria.tracks) { for (const t of criteria.tracks) { - const trackSearchRes = await ChallengeTrackService.searchChallengeTracks({ abbreviation: t }) + const trackSearchRes = await ChallengeTrackService.searchChallengeTracks({ + abbreviation: t, + }); if (trackSearchRes.total > 0) { - includedTrackIds.push(_.get(trackSearchRes, 'result[0].id')) + includedTrackIds.push(_.get(trackSearchRes, "result[0].id")); } } } if (criteria.typeId) { - includedTypeIds.push(criteria.typeId) + includedTypeIds.push(criteria.typeId); } if (criteria.trackId) { - includedTrackIds.push(criteria.trackId) + includedTrackIds.push(criteria.trackId); } _.forIn(_.pick(criteria, matchPhraseKeys), (value, key) => { if (!_.isUndefined(value)) { - const filter = { match_phrase: {} } - filter.match_phrase[key] = value - boolQuery.push(filter) + const filter = { match_phrase: {} }; + filter.match_phrase[key] = value; + boolQuery.push(filter); } - }) + }); _.forEach(_.keys(criteria), (key) => { - if (_.toString(key).indexOf('meta.') > -1) { + if (_.toString(key).indexOf("meta.") > -1) { // Parse and use metadata key if (!_.isUndefined(criteria[key])) { - const metaKey = key.split('meta.')[1] + const metaKey = key.split("meta.")[1]; boolQuery.push({ bool: { must: [ - { match_phrase: { 'metadata.name': metaKey } }, - { match_phrase: { 'metadata.value': _.toString(criteria[key]) } } - ] - } - }) + { match_phrase: { "metadata.name": metaKey } }, + { match_phrase: { "metadata.value": _.toString(criteria[key]) } }, + ], + }, + }); } } - }) + }); if (includedTypeIds.length > 0) { boolQuery.push({ bool: { - should: _.map(includedTypeIds, t => ({ match_phrase: { typeId: t } })) - } - }) + should: _.map(includedTypeIds, (t) => ({ + match_phrase: { typeId: t }, + })), + }, + }); } if (includedTrackIds.length > 0) { boolQuery.push({ bool: { - should: _.map(includedTrackIds, t => ({ match_phrase: { trackId: t } })) - } - }) + should: _.map(includedTrackIds, (t) => ({ + match_phrase: { trackId: t }, + })), + }, + }); } - const multiMatchQuery = [] + const multiMatchQuery = []; if (criteria.search) { multiMatchQuery.push({ // exact match multi_match: { query: criteria.search, - fields: [ - 'name.text^7', - 'tags^3', - 'description^2' - ], - type: 'phrase_prefix', - boost: 5 - } - }) + fields: ["name.text^7", "tags^3", "description^2"], + type: "phrase_prefix", + boost: 5, + }, + }); multiMatchQuery.push({ // match 100% words multi_match: { query: criteria.search, - fields: [ - 'name.text^3.0', - 'tags^2.5', - 'description^1.0' - ], - type: 'most_fields', - minimum_should_match: '100%', - boost: 2.5 - } - }) + fields: ["name.text^3.0", "tags^2.5", "description^1.0"], + type: "most_fields", + minimum_should_match: "100%", + boost: 2.5, + }, + }); multiMatchQuery.push({ // fuzzy match multi_match: { query: criteria.search, - fields: [ - 'name.text^2.5', - 'tags^1.5', - 'description^1.0' + fields: ["name.text^2.5", "tags^1.5", "description^1.0"], + type: "most_fields", + minimum_should_match: "50%", + fuzziness: "AUTO", + boost: 1, + }, + }); + boolQuery.push({ + bool: { + should: [ + { wildcard: { name: `*${criteria.search}*` } }, + { wildcard: { name: `${criteria.search}*` } }, + { wildcard: { name: `*${criteria.search}` } }, + { match_phrase: { tags: criteria.search } }, ], - type: 'most_fields', - minimum_should_match: '50%', - fuzziness: 'AUTO', - boost: 1 - } - }) - boolQuery.push({ bool: { - should: [ - { wildcard: { name: `*${criteria.search}*` } }, - { wildcard: { name: `${criteria.search}*` } }, - { wildcard: { name: `*${criteria.search}` } }, - { match_phrase: { tags: criteria.search } } - ] - } }) + }, + }); } else { if (criteria.name) { - boolQuery.push({ bool: { - should: [ - { wildcard: { name: `*${criteria.name}*` } }, - { wildcard: { name: `${criteria.name}*` } }, - { wildcard: { name: `*${criteria.name}` } } - ] - } }) + boolQuery.push({ + bool: { + should: [ + { wildcard: { name: `*${criteria.name}*` } }, + { wildcard: { name: `${criteria.name}*` } }, + { wildcard: { name: `*${criteria.name}` } }, + ], + }, + }); } if (criteria.description) { - boolQuery.push({ match_phrase_prefix: { 'description': criteria.description } }) + boolQuery.push({ + match_phrase_prefix: { description: criteria.description }, + }); } } // 'search', 'name', 'description' fields should be sorted by function score unless sortBy param provided. - if (!criteria.sortBy && ( - criteria.search || - criteria.name || - criteria.description - )) { - sortByScore = true + if (!criteria.sortBy && (criteria.search || criteria.name || criteria.description)) { + sortByScore = true; } if (criteria.tag) { - boolQuery.push({ match_phrase: { tags: criteria.tag } }) + boolQuery.push({ match_phrase: { tags: criteria.tag } }); } if (criteria.tags) { boolQuery.push({ bool: { - [criteria.includeAllTags ? 'must' : 'should']: _.map(criteria.tags, t => ({ match_phrase: { tags: t } })) - } - }) + [criteria.includeAllTags ? "must" : "should"]: _.map(criteria.tags, (t) => ({ + match_phrase: { tags: t }, + })), + }, + }); } if (criteria.totalPrizesFrom || criteria.totalPrizesTo) { - const prizeRangeQuery = {} + const prizeRangeQuery = {}; if (criteria.totalPrizesFrom) { - prizeRangeQuery.gte = criteria.totalPrizesFrom + prizeRangeQuery.gte = criteria.totalPrizesFrom; } if (criteria.totalPrizesTo) { - prizeRangeQuery.lte = criteria.totalPrizesTo + prizeRangeQuery.lte = criteria.totalPrizesTo; } - boolQuery.push({ range: { 'overview.totalPrizes': prizeRangeQuery } }) + boolQuery.push({ range: { "overview.totalPrizes": prizeRangeQuery } }); } if (criteria.useSchedulingAPI) { - boolQuery.push({ match_phrase: { 'legacy.useSchedulingAPI': criteria.useSchedulingAPI } }) + boolQuery.push({ + match_phrase: { "legacy.useSchedulingAPI": criteria.useSchedulingAPI }, + }); } if (criteria.selfService) { - boolQuery.push({ match_phrase: { 'legacy.selfService': criteria.selfService } }) + boolQuery.push({ + match_phrase: { "legacy.selfService": criteria.selfService }, + }); } if (criteria.selfServiceCopilot) { - boolQuery.push({ match_phrase: { 'legacy.selfServiceCopilot': criteria.selfServiceCopilot } }) + boolQuery.push({ + match_phrase: { + "legacy.selfServiceCopilot": criteria.selfServiceCopilot, + }, + }); } if (criteria.forumId) { - boolQuery.push({ match_phrase: { 'legacy.forumId': criteria.forumId } }) + boolQuery.push({ match_phrase: { "legacy.forumId": criteria.forumId } }); } if (criteria.reviewType) { - boolQuery.push({ match_phrase: { 'legacy.reviewType': criteria.reviewType } }) + boolQuery.push({ + match_phrase: { "legacy.reviewType": criteria.reviewType }, + }); } if (criteria.confidentialityType) { - boolQuery.push({ match_phrase: { 'legacy.confidentialityType': criteria.confidentialityType } }) + boolQuery.push({ + match_phrase: { + "legacy.confidentialityType": criteria.confidentialityType, + }, + }); } if (criteria.directProjectId) { - boolQuery.push({ match_phrase: { 'legacy.directProjectId': criteria.directProjectId } }) + boolQuery.push({ + match_phrase: { "legacy.directProjectId": criteria.directProjectId }, + }); } if (criteria.currentPhaseName) { - boolQuery.push({ match_phrase: { 'currentPhaseNames': criteria.currentPhaseName } }) + boolQuery.push({ + match_phrase: { currentPhaseNames: criteria.currentPhaseName }, + }); } if (criteria.createdDateStart) { - boolQuery.push({ range: { created: { gte: criteria.createdDateStart } } }) + boolQuery.push({ range: { created: { gte: criteria.createdDateStart } } }); } if (criteria.createdDateEnd) { - boolQuery.push({ range: { created: { lte: criteria.createdDateEnd } } }) + boolQuery.push({ range: { created: { lte: criteria.createdDateEnd } } }); } if (criteria.registrationStartDateStart) { - boolQuery.push({ range: { registrationStartDate: { gte: criteria.registrationStartDateStart } } }) + boolQuery.push({ + range: { + registrationStartDate: { gte: criteria.registrationStartDateStart }, + }, + }); } if (criteria.registrationStartDateEnd) { - boolQuery.push({ range: { registrationStartDate: { lte: criteria.registrationStartDateEnd } } }) + boolQuery.push({ + range: { + registrationStartDate: { lte: criteria.registrationStartDateEnd }, + }, + }); } if (criteria.registrationEndDateStart) { - boolQuery.push({ range: { registrationEndDate: { gte: criteria.registrationEndDateStart } } }) + boolQuery.push({ + range: { + registrationEndDate: { gte: criteria.registrationEndDateStart }, + }, + }); } if (criteria.registrationEndDateEnd) { - boolQuery.push({ range: { registrationEndDate: { lte: criteria.registrationEndDateEnd } } }) + boolQuery.push({ + range: { registrationEndDate: { lte: criteria.registrationEndDateEnd } }, + }); } if (criteria.submissionStartDateStart) { - boolQuery.push({ range: { submissionStartDate: { gte: criteria.submissionStartDateStart } } }) + boolQuery.push({ + range: { + submissionStartDate: { gte: criteria.submissionStartDateStart }, + }, + }); } if (criteria.submissionStartDateEnd) { - boolQuery.push({ range: { submissionStartDate: { lte: criteria.submissionStartDateEnd } } }) + boolQuery.push({ + range: { submissionStartDate: { lte: criteria.submissionStartDateEnd } }, + }); } if (criteria.submissionEndDateStart) { - boolQuery.push({ range: { submissionEndDate: { gte: criteria.submissionEndDateStart } } }) + boolQuery.push({ + range: { submissionEndDate: { gte: criteria.submissionEndDateStart } }, + }); } if (criteria.submissionEndDateEnd) { - boolQuery.push({ range: { submissionEndDate: { lte: criteria.submissionEndDateEnd } } }) + boolQuery.push({ + range: { submissionEndDate: { lte: criteria.submissionEndDateEnd } }, + }); } if (criteria.updatedDateStart) { - boolQuery.push({ range: { updated: { gte: criteria.updatedDateStart } } }) + boolQuery.push({ range: { updated: { gte: criteria.updatedDateStart } } }); } if (criteria.updatedDateEnd) { - boolQuery.push({ range: { updated: { lte: criteria.updatedDateEnd } } }) + boolQuery.push({ range: { updated: { lte: criteria.updatedDateEnd } } }); } if (criteria.startDateStart) { - boolQuery.push({ range: { startDate: { gte: criteria.startDateStart } } }) + boolQuery.push({ range: { startDate: { gte: criteria.startDateStart } } }); } if (criteria.startDateEnd) { - boolQuery.push({ range: { startDate: { lte: criteria.startDateEnd } } }) + boolQuery.push({ range: { startDate: { lte: criteria.startDateEnd } } }); } if (criteria.endDateStart) { - boolQuery.push({ range: { endDate: { gte: criteria.endDateStart } } }) + boolQuery.push({ range: { endDate: { gte: criteria.endDateStart } } }); } if (criteria.endDateEnd) { - boolQuery.push({ range: { endDate: { lte: criteria.endDateEnd } } }) + boolQuery.push({ range: { endDate: { lte: criteria.endDateEnd } } }); } - let sortByProp = criteria.sortBy ? criteria.sortBy : 'created' - const sortOrderProp = criteria.sortOrder ? criteria.sortOrder : 'desc' + let sortByProp = criteria.sortBy ? criteria.sortBy : "created"; + const sortOrderProp = criteria.sortOrder ? criteria.sortOrder : "desc"; - const mustQuery = [] + const mustQuery = []; - const groupsQuery = [] + const groupsQuery = []; if (criteria.tco) { - boolQuery.push({ match_phrase_prefix: { 'events.key': 'tco' } }) + boolQuery.push({ match_phrase_prefix: { "events.key": "tco" } }); } if (criteria.events) { boolQuery.push({ bool: { - [criteria.includeAllEvents ? 'must' : 'should']: _.map(criteria.events, e => ({ match_phrase: { 'events.key': e } })) - } - }) + [criteria.includeAllEvents ? "must" : "should"]: _.map(criteria.events, (e) => ({ + match_phrase: { "events.key": e }, + })), + }, + }); } - const mustNotQuery = [] + const mustNotQuery = []; - let groupsToFilter = [] - let accessibleGroups = [] + let groupsToFilter = []; + let accessibleGroups = []; - if (currentUser && !currentUser.isMachine && !hasAdminRole) { - accessibleGroups = await helper.getCompleteUserGroupTreeIds(currentUser.userId) + if (currentUser && !currentUser.isMachine && !_hasAdminRole) { + accessibleGroups = await helper.getCompleteUserGroupTreeIds(currentUser.userId); } // Filter all groups from the criteria to make sure the user can access those @@ -483,50 +553,48 @@ async function searchChallenges (currentUser, criteria) { // check group access if (_.isUndefined(currentUser)) { if (criteria.group) { - const group = await helper.getGroupById(criteria.group) + const group = await helper.getGroupById(criteria.group); if (group && !group.privateGroup) { - groupsToFilter.push(criteria.group) + groupsToFilter.push(criteria.group); } } if (criteria.groups && criteria.groups.length > 0) { - const promises = [] + const promises = []; _.each(criteria.groups, (g) => { promises.push( (async () => { - const group = await helper.getGroupById(g) + const group = await helper.getGroupById(g); if (group && !group.privateGroup) { - groupsToFilter.push(g) + groupsToFilter.push(g); } })() - ) - }) - await Promise.all(promises) + ); + }); + await Promise.all(promises); } - } else if (!currentUser.isMachine && !hasAdminRole) { + } else if (!currentUser.isMachine && !_hasAdminRole) { if (accessibleGroups.includes(criteria.group)) { - groupsToFilter.push(criteria.group) + groupsToFilter.push(criteria.group); } if (criteria.groups && criteria.groups.length > 0) { _.each(criteria.groups, (g) => { if (accessibleGroups.includes(g)) { - groupsToFilter.push(g) + groupsToFilter.push(g); } - }) + }); } } else { - groupsToFilter = [ - ...(criteria.groups ? criteria.groups : []) - ] + groupsToFilter = [...(criteria.groups ? criteria.groups : [])]; if (criteria.group) { - groupsToFilter.push(criteria.group) + groupsToFilter.push(criteria.group); } } - groupsToFilter = _.uniq(groupsToFilter) + groupsToFilter = _.uniq(groupsToFilter); if (groupsToFilter.length === 0) { // User can't access any of the groups from the filters // We return an empty array as the result - return { total: 0, page, perPage, result: [] } + return { total: 0, page, perPage, result: [] }; } } @@ -534,31 +602,31 @@ async function searchChallenges (currentUser, criteria) { // Return public challenges + challenges from groups that the user has access to if (_.isUndefined(currentUser)) { // If the user is not authenticated, only query challenges that don't have a group - mustNotQuery.push({ exists: { field: 'groups' } }) - } else if (!currentUser.isMachine && !hasAdminRole) { + mustNotQuery.push({ exists: { field: "groups" } }); + } else if (!currentUser.isMachine && !_hasAdminRole) { // If the user is not M2M and is not an admin, return public + challenges from groups the user can access _.each(accessibleGroups, (g) => { - groupsQuery.push({ match_phrase: { groups: g } }) - }) + groupsQuery.push({ match_phrase: { groups: g } }); + }); // include public challenges - groupsQuery.push({ bool: { must_not: { exists: { field: 'groups' } } } }) + groupsQuery.push({ bool: { must_not: { exists: { field: "groups" } } } }); } } else { _.each(groupsToFilter, (g) => { - groupsQuery.push({ match_phrase: { groups: g } }) - }) + groupsQuery.push({ match_phrase: { groups: g } }); + }); } if (criteria.ids) { boolQuery.push({ bool: { - should: _.map(criteria.ids, id => ({ match_phrase: { _id: id } })) - } - }) + should: _.map(criteria.ids, (id) => ({ match_phrase: { _id: id } })), + }, + }); } - const accessQuery = [] - let memberChallengeIds + const accessQuery = []; + let memberChallengeIds; // FIXME: This is wrong! // if (!_.isUndefined(currentUser) && currentUser.handle) { @@ -567,26 +635,26 @@ async function searchChallenges (currentUser, criteria) { if (criteria.memberId) { // logger.error(`memberId ${criteria.memberId}`) - memberChallengeIds = await helper.listChallengesByMember(criteria.memberId) + memberChallengeIds = await helper.listChallengesByMember(criteria.memberId); // logger.error(`response ${JSON.stringify(ids)}`) - accessQuery.push({ terms: { _id: memberChallengeIds } }) - } else if (currentUser && !hasAdminRole && !_.get(currentUser, 'isMachine', false)) { - memberChallengeIds = await helper.listChallengesByMember(currentUser.userId) + accessQuery.push({ terms: { _id: memberChallengeIds } }); + } else if (currentUser && !_hasAdminRole && !_.get(currentUser, "isMachine", false)) { + memberChallengeIds = await helper.listChallengesByMember(currentUser.userId); } if (accessQuery.length > 0) { mustQuery.push({ bool: { - should: accessQuery - } - }) + should: accessQuery, + }, + }); } // FIXME: Tech Debt - let excludeTasks = true + let excludeTasks = true; // if you're an admin or m2m, security rules wont be applied - if (currentUser && (hasAdminRole || _.get(currentUser, 'isMachine', false))) { - excludeTasks = false + if (currentUser && (_hasAdminRole || _.get(currentUser, "isMachine", false))) { + excludeTasks = false; } /** @@ -597,299 +665,326 @@ async function searchChallenges (currentUser, criteria) { * For admins/m2m: * - All tasks will be returned */ - if (currentUser && (hasAdminRole || _.get(currentUser, 'isMachine', false))) { + if (currentUser && (_hasAdminRole || _.get(currentUser, "isMachine", false))) { // For admins/m2m, allow filtering based on task properties if (criteria.isTask) { - boolQuery.push({ match_phrase: { 'task.isTask': criteria.isTask } }) + boolQuery.push({ match_phrase: { "task.isTask": criteria.isTask } }); } if (criteria.taskIsAssigned) { - boolQuery.push({ match_phrase: { 'task.isAssigned': criteria.taskIsAssigned } }) + boolQuery.push({ + match_phrase: { "task.isAssigned": criteria.taskIsAssigned }, + }); } if (criteria.taskMemberId || criteria.memberId) { - boolQuery.push({ match_phrase: { 'task.memberId': criteria.taskMemberId || criteria.memberId } }) + boolQuery.push({ + match_phrase: { + "task.memberId": criteria.taskMemberId || criteria.memberId, + }, + }); } } else if (excludeTasks) { mustQuery.push({ bool: { should: [ - ...(_.get(memberChallengeIds, 'length', 0) > 0 ? [{ bool: { should: [ { terms: { _id: memberChallengeIds } } ] } }] : []), - { bool: { must_not: { exists: { field: 'task.isTask' } } } }, - { match_phrase: { 'task.isTask': false } }, + ...(_.get(memberChallengeIds, "length", 0) > 0 + ? [{ bool: { should: [{ terms: { _id: memberChallengeIds } }] } }] + : []), + { bool: { must_not: { exists: { field: "task.isTask" } } } }, + { match_phrase: { "task.isTask": false } }, { bool: { must: [ - { match_phrase: { 'task.isTask': true } }, - { match_phrase: { 'task.isAssigned': false } } - ] - } + { match_phrase: { "task.isTask": true } }, + { match_phrase: { "task.isAssigned": false } }, + ], + }, }, - ...( - currentUser && !hasAdminRole && !_.get(currentUser, 'isMachine', false) - ? [{ match_phrase: { 'task.memberId': currentUser.userId } }] - : [] - ) - ] - } - }) + ...(currentUser && !_hasAdminRole && !_.get(currentUser, "isMachine", false) + ? [{ match_phrase: { "task.memberId": currentUser.userId } }] + : []), + ], + }, + }); } if (!includeSelfService) { mustQuery.push({ bool: { should: [ - { bool: { must_not: { exists: { field: 'legacy.selfService' } } } }, - ...(currentUser ? [ - { - bool: { - must: [ - { bool: { must_not: { match_phrase: { 'status': constants.challengeStatuses.New } } } }, - { bool: { must_not: { match_phrase: { 'status': constants.challengeStatuses.Draft } } } }, - { bool: { must_not: { match_phrase: { 'status': constants.challengeStatuses.Approved } } } } - ] - } - }, - { bool: { must: { match_phrase: { 'createdBy': currentUser.handle } } } } - ] : [ - { - bool: { - should: [ - { bool: { must: { match_phrase: { 'status': constants.challengeStatuses.Active } } } }, - { bool: { must: { match_phrase: { 'status': constants.challengeStatuses.Completed } } } } - ] - } - } - ]) - ] - } - }) + { bool: { must_not: { exists: { field: "legacy.selfService" } } } }, + ...(currentUser + ? [ + { + bool: { + must: [ + { + bool: { + must_not: { + match_phrase: { + status: constants.challengeStatuses.New, + }, + }, + }, + }, + { + bool: { + must_not: { + match_phrase: { + status: constants.challengeStatuses.Draft, + }, + }, + }, + }, + { + bool: { + must_not: { + match_phrase: { + status: constants.challengeStatuses.Approved, + }, + }, + }, + }, + ], + }, + }, + { + bool: { + must: { match_phrase: { createdBy: currentUser.handle } }, + }, + }, + ] + : [ + { + bool: { + should: [ + { + bool: { + must: { + match_phrase: { + status: constants.challengeStatuses.Active, + }, + }, + }, + }, + { + bool: { + must: { + match_phrase: { + status: constants.challengeStatuses.Completed, + }, + }, + }, + }, + ], + }, + }, + ]), + ], + }, + }); } if (groupsQuery.length > 0) { mustQuery.push({ bool: { - should: groupsQuery - } - }) + should: groupsQuery, + }, + }); } if (multiMatchQuery) { mustQuery.push({ bool: { - should: multiMatchQuery - } - }) + should: multiMatchQuery, + }, + }); } if (boolQuery.length > 0) { mustQuery.push({ bool: { - filter: boolQuery - } - }) + filter: boolQuery, + }, + }); } let finalQuery = { - bool: {} - } + bool: {}, + }; if (mustQuery.length > 0) { - finalQuery.bool.must = mustQuery + finalQuery.bool.must = mustQuery; } if (mustNotQuery.length > 0) { - finalQuery.bool.must_not = mustNotQuery + finalQuery.bool.must_not = mustNotQuery; if (!finalQuery.bool.must) { - finalQuery.bool.must = mustQuery + finalQuery.bool.must = mustQuery; } } // if none of the above were set, match all if (!finalQuery.bool.must) { finalQuery = { - match_all: {} - } + match_all: {}, + }; } const esQuery = { - index: config.get('ES.ES_INDEX'), - type: config.get('ES.ES_TYPE'), + index: config.get("ES.ES_INDEX"), size: perPage, from: (page - 1) * perPage, // Es Index starts from 0 body: { query: finalQuery, - sort: [sortByScore ? { '_score': { 'order': 'desc' } } : { [sortByProp]: { 'order': sortOrderProp, 'missing': '_last', 'unmapped_type': 'String' } }] - } - } + sort: [ + sortByScore + ? { _score: { order: "desc" } } + : { + [sortByProp]: { + order: sortOrderProp, + missing: "_last", + unmapped_type: "String", + }, + }, + ], + }, + }; - logger.debug(`es Query ${JSON.stringify(esQuery, null, 4)}`) + logger.debug(`es Query ${JSON.stringify(esQuery, null, 4)}`); // Search with constructed query - let docs + let docs; try { - docs = await esClient.search(esQuery) + docs = + config.get("ES.OPENSEARCH") == "false" + ? await esClient.search(esQuery) + : (await esClient.search(esQuery)).body; } catch (e) { // Catch error when the ES is fresh and has no data - logger.error(`Query Error from ES ${JSON.stringify(e, null, 4)}`) + logger.error(`Query Error from ES ${JSON.stringify(e, null, 4)}`); docs = { hits: { total: 0, - hits: [] - } - } + hits: [], + }, + }; } // Extract data from hits - const total = docs.hits.total - let result = _.map(docs.hits.hits, item => item._source) + const total = docs.hits.total; + let result = _.map(docs.hits.hits, (item) => item._source); // Hide privateDescription for non-register challenges if (currentUser) { - if (!currentUser.isMachine && !hasAdminRole) { - result = _.each(result, (val) => _.unset(val, 'billing')) - const ids = await helper.listChallengesByMember(currentUser.userId) + if (!currentUser.isMachine && !_hasAdminRole) { + result = _.each(result, (val) => _.unset(val, "billing")); + const ids = await helper.listChallengesByMember(currentUser.userId); result = _.each(result, (val) => { if (!_.includes(ids, val.id)) { - _.unset(val, 'privateDescription') + _.unset(val, "privateDescription"); } - }) + }); } } else { - result = _.each(result, val => { - _.unset(val, 'billing') - _.unset(val, 'privateDescription') - return val - }) + result = _.each(result, (val) => { + _.unset(val, "billing"); + _.unset(val, "privateDescription"); + return val; + }); } - if (criteria.isLightweight === 'true') { - result = _.each(result, val => { + if (criteria.isLightweight === "true") { + result = _.each(result, (val) => { // _.unset(val, 'terms') - _.unset(val, 'description') - _.unset(val, 'privateDescription') - return val - }) - } - - const challengeTypeList = await ChallengeTypeService.searchChallengeTypes({}) - const typeMap = new Map() - _.each(challengeTypeList.result, e => { - typeMap.set(e.id, e.name) - }) - - _.each(result, element => { - element.type = typeMap.get(element.typeId) || 'Code' - }) - _.each(result, async element => { - await getPhasesAndPopulate(element) + _.unset(val, "description"); + _.unset(val, "privateDescription"); + return val; + }); + } + + const challengeTypeList = await ChallengeTypeService.searchChallengeTypes({}); + const typeMap = new Map(); + _.each(challengeTypeList.result, (e) => { + typeMap.set(e.id, e.name); + }); + + _.each(result, (element) => { + element.type = typeMap.get(element.typeId) || "Code"; + }); + _.each(result, async (element) => { + await getPhasesAndPopulate(element); if (element.status !== constants.challengeStatuses.Completed) { - _.unset(element, 'winners') + _.unset(element, "winners"); } - }) + }); - return { total, page, perPage, result } + return { total, page, perPage, result }; } - searchChallenges.schema = { currentUser: Joi.any(), - criteria: Joi.object().keys({ - page: Joi.page(), - perPage: Joi.perPage(), - id: Joi.optionalId(), - selfService: Joi.boolean(), - selfServiceCopilot: Joi.string(), - confidentialityType: Joi.string(), - directProjectId: Joi.number(), - typeIds: Joi.array().items(Joi.optionalId()), - trackIds: Joi.array().items(Joi.optionalId()), - types: Joi.array().items(Joi.string()), - tracks: Joi.array().items(Joi.string()), - typeId: Joi.optionalId(), - trackId: Joi.optionalId(), - type: Joi.string(), - track: Joi.string(), - name: Joi.string(), - search: Joi.string(), - description: Joi.string(), - timelineTemplateId: Joi.string(), // Joi.optionalId(), - reviewType: Joi.string(), - tag: Joi.string(), - tags: Joi.array().items(Joi.string()), - includeAllTags: Joi.boolean().default(true), - projectId: Joi.number().integer().positive(), - forumId: Joi.number().integer(), - legacyId: Joi.number().integer().positive(), - status: Joi.string().valid(_.values(constants.challengeStatuses)), - group: Joi.string(), - startDateStart: Joi.date(), - startDateEnd: Joi.date(), - endDateStart: Joi.date(), - endDateEnd: Joi.date(), - currentPhaseName: Joi.string(), - createdDateStart: Joi.date(), - createdDateEnd: Joi.date(), - updatedDateStart: Joi.date(), - updatedDateEnd: Joi.date(), - registrationStartDateStart: Joi.date(), - registrationStartDateEnd: Joi.date(), - registrationEndDateStart: Joi.date(), - registrationEndDateEnd: Joi.date(), - submissionStartDateStart: Joi.date(), - submissionStartDateEnd: Joi.date(), - submissionEndDateStart: Joi.date(), - submissionEndDateEnd: Joi.date(), - createdBy: Joi.string(), - updatedBy: Joi.string(), - isLightweight: Joi.boolean().default(false), - memberId: Joi.string(), - sortBy: Joi.string().valid(_.values(constants.validChallengeParams)), - sortOrder: Joi.string().valid(['asc', 'desc']), - groups: Joi.array().items(Joi.optionalId()).unique().min(1), - ids: Joi.array().items(Joi.optionalId()).unique().min(1), - isTask: Joi.boolean(), - taskIsAssigned: Joi.boolean(), - taskMemberId: Joi.string(), - events: Joi.array().items(Joi.string()), - includeAllEvents: Joi.boolean().default(true), - useSchedulingAPI: Joi.boolean(), - totalPrizesFrom: Joi.number().min(0), - totalPrizesTo: Joi.number().min(0), - tco: Joi.boolean().default(false) - }).unknown(true) -} - -/** - * Validate the challenge data. - * @param {Object} challenge the challenge data - */ -async function validateChallengeData (challenge) { - let type - let track - if (challenge.typeId) { - try { - type = await helper.getById('ChallengeType', challenge.typeId) - } catch (e) { - if (e.name === 'NotFoundError') { - throw new errors.BadRequestError(`No challenge type found with id: ${challenge.typeId}.`) - } else { - throw e - } - } - } - if (challenge.trackId) { - try { - track = await helper.getById('ChallengeTrack', challenge.trackId) - } catch (e) { - if (e.name === 'NotFoundError') { - throw new errors.BadRequestError(`No challenge track found with id: ${challenge.trackId}.`) - } else { - throw e - } - } - } - if (challenge.timelineTemplateId) { - const template = await helper.getById('TimelineTemplate', challenge.timelineTemplateId) - if (!template.isActive) { - throw new errors.BadRequestError(`The timeline template with id: ${challenge.timelineTemplateId} is inactive`) - } - } - return { type, track } -} + criteria: Joi.object() + .keys({ + page: Joi.page(), + perPage: Joi.perPage(), + id: Joi.optionalId(), + selfService: Joi.boolean(), + selfServiceCopilot: Joi.string(), + confidentialityType: Joi.string(), + directProjectId: Joi.number(), + typeIds: Joi.array().items(Joi.optionalId()), + trackIds: Joi.array().items(Joi.optionalId()), + types: Joi.array().items(Joi.string()), + tracks: Joi.array().items(Joi.string()), + typeId: Joi.optionalId(), + trackId: Joi.optionalId(), + type: Joi.string(), + track: Joi.string(), + name: Joi.string(), + search: Joi.string(), + description: Joi.string(), + timelineTemplateId: Joi.string(), // Joi.optionalId(), + reviewType: Joi.string(), + tag: Joi.string(), + tags: Joi.array().items(Joi.string()), + includeAllTags: Joi.boolean().default(true), + projectId: Joi.number().integer().positive(), + forumId: Joi.number().integer(), + legacyId: Joi.number().integer().positive(), + status: Joi.string().valid(_.values(constants.challengeStatuses)), + group: Joi.string(), + startDateStart: Joi.date(), + startDateEnd: Joi.date(), + endDateStart: Joi.date(), + endDateEnd: Joi.date(), + currentPhaseName: Joi.string(), + createdDateStart: Joi.date(), + createdDateEnd: Joi.date(), + updatedDateStart: Joi.date(), + updatedDateEnd: Joi.date(), + registrationStartDateStart: Joi.date(), + registrationStartDateEnd: Joi.date(), + registrationEndDateStart: Joi.date(), + registrationEndDateEnd: Joi.date(), + submissionStartDateStart: Joi.date(), + submissionStartDateEnd: Joi.date(), + submissionEndDateStart: Joi.date(), + submissionEndDateEnd: Joi.date(), + createdBy: Joi.string(), + updatedBy: Joi.string(), + isLightweight: Joi.boolean().default(false), + memberId: Joi.string(), + sortBy: Joi.string().valid(_.values(constants.validChallengeParams)), + sortOrder: Joi.string().valid(["asc", "desc"]), + groups: Joi.array().items(Joi.optionalId()).unique().min(1), + ids: Joi.array().items(Joi.optionalId()).unique().min(1), + isTask: Joi.boolean(), + taskIsAssigned: Joi.boolean(), + taskMemberId: Joi.string(), + events: Joi.array().items(Joi.string()), + includeAllEvents: Joi.boolean().default(true), + useSchedulingAPI: Joi.boolean(), + totalPrizesFrom: Joi.number().min(0), + totalPrizesTo: Joi.number().min(0), + tco: Joi.boolean().default(false), + }) + .unknown(true), +}; /** * Create challenge. @@ -898,283 +993,299 @@ async function validateChallengeData (challenge) { * @param {String} userToken the user token * @returns {Object} the created challenge */ -async function createChallenge (currentUser, challenge, userToken) { - try { - if (challenge.legacy.selfService) { - if (!challenge.projectId) { - const selfServiceProjectName = `Self service - ${currentUser.handle} - ${challenge.name}` - challenge.projectId = await helper.createSelfServiceProject(selfServiceProjectName, 'N/A', config.NEW_SELF_SERVICE_PROJECT_TYPE, userToken) - } - } else if (!challenge.projectId) { - throw new errors.BadRequestError('The projectId is required') - } - } catch (e) { - throw new errors.ServiceUnavailableError('Fail to create a self-service project') - } - if (challenge.legacy.selfService && challenge.metadata && challenge.metadata.length > 0) { - for (const entry of challenge.metadata) { - if (challenge.description.includes(`{{${entry.name}}}`)) { - challenge.description = challenge.description.split(`{{${entry.name}}}`).join(entry.value) +async function createChallenge(currentUser, challenge, userToken) { + await challengeHelper.validateCreateChallengeRequest(currentUser, challenge); + + if (challenge.legacy.selfService) { + // if self-service, create a new project (what about if projectId is provided in the payload? confirm with business!) + if (!challenge.projectId) { + const selfServiceProjectName = `Self service - ${currentUser.handle} - ${challenge.name}`; + challenge.projectId = await helper.createSelfServiceProject( + selfServiceProjectName, + "N/A", + config.NEW_SELF_SERVICE_PROJECT_TYPE + ); + } + + if (challenge.metadata && challenge.metadata.length > 0) { + for (const entry of challenge.metadata) { + if (challenge.description.includes(`{{${entry.name}}}`)) { + challenge.description = challenge.description + .split(`{{${entry.name}}}`) + .join(entry.value); + } } } } - if (!_.isUndefined(_.get(challenge, 'legacy.reviewType'))) { - _.set(challenge, 'legacy.reviewType', _.toUpper(_.get(challenge, 'legacy.reviewType'))) + + /** Ensure project exists, and set direct project id, billing account id & markup */ + const { projectId } = challenge; + + const { directProjectId } = await projectHelper.getProject(projectId, currentUser); + const { billingAccountId, markup } = await projectHelper.getProjectBillingInformation(projectId); + + _.set(challenge, "legacy.directProjectId", directProjectId); + _.set(challenge, "billing.billingAccountId", billingAccountId); + _.set(challenge, "billing.markup", markup || 0); + + if (!_.isUndefined(_.get(challenge, "legacy.reviewType"))) { + _.set(challenge, "legacy.reviewType", _.toUpper(_.get(challenge, "legacy.reviewType"))); } - challenge.name = xss(challenge.name) - challenge.description = xss(challenge.description) + if (!challenge.status) { - challenge.status = constants.challengeStatuses.New + challenge.status = constants.challengeStatuses.New; } + if (!challenge.startDate) { - challenge.startDate = new Date() - } - if (challenge.status === constants.challengeStatuses.Active) { - throw new errors.BadRequestError('You cannot create an Active challenge. Please create a Draft challenge and then change the status to Active.') - } - const { directProjectId } = await helper.ensureProjectExist(challenge.projectId, currentUser) - if (_.get(challenge, 'legacy.pureV5Task') || _.get(challenge, 'legacy.pureV5')) { - _.set(challenge, 'legacy.directProjectId', directProjectId) - } - const { track, type } = await validateChallengeData(challenge) - const { billingAccountId, markup } = await helper.getProjectBillingInformation(_.get(challenge, 'projectId')) - if (billingAccountId && _.isUndefined(_.get(challenge, 'billing.billingAccountId'))) { - _.set(challenge, 'billing.billingAccountId', billingAccountId) - _.set(challenge, 'billing.markup', markup || 0) + challenge.startDate = new Date().toISOString(); + } else { + challenge.startDate = new Date(challenge.startDate).toISOString(); } - if (_.get(type, 'isTask')) { - _.set(challenge, 'task.isTask', true) - if (_.isUndefined(_.get(challenge, 'task.isAssigned'))) { - _.set(challenge, 'task.isAssigned', false) + + const { track, type } = await challengeHelper.validateAndGetChallengeTypeAndTrack(challenge); + + if (_.get(type, "isTask")) { + _.set(challenge, "task.isTask", true); + if (_.isUndefined(_.get(challenge, "task.isAssigned"))) { + _.set(challenge, "task.isAssigned", false); } - if (_.isUndefined(_.get(challenge, 'task.memberId'))) { - _.set(challenge, 'task.memberId', null) + if (_.isUndefined(_.get(challenge, "task.memberId"))) { + _.set(challenge, "task.memberId", null); } else { - throw new errors.BadRequestError(`Cannot assign a member before the challenge gets created.`) - } - } - if (challenge.discussions && challenge.discussions.length > 0) { - for (let i = 0; i < challenge.discussions.length; i += 1) { - challenge.discussions[i].id = uuid() - challenge.discussions[i].name = challenge.discussions[i].name.substring(0, config.FORUM_TITLE_LENGTH_LIMIT) + throw new errors.BadRequestError(`Cannot assign a member before the challenge gets created.`); } } + if (challenge.phases && challenge.phases.length > 0) { - await phaseHelper.validatePhases(challenge.phases) + await PhaseService.validatePhases(challenge.phases); } - helper.ensureNoDuplicateOrNullElements(challenge.tags, 'tags') - helper.ensureNoDuplicateOrNullElements(challenge.groups, 'groups') - // helper.ensureNoDuplicateOrNullElements(challenge.terms, 'terms') - // helper.ensureNoDuplicateOrNullElements(challenge.events, 'events') - - // check groups authorization - await helper.ensureAccessibleByGroupsAccess(currentUser, challenge) // populate phases if (!challenge.timelineTemplateId) { if (challenge.typeId && challenge.trackId) { - const supportedTemplates = await ChallengeTimelineTemplateService.searchChallengeTimelineTemplates({ - typeId: challenge.typeId, - trackId: challenge.trackId, - isDefault: true - }) - const challengeTimelineTemplate = supportedTemplates.result[0] + const supportedTemplates = + await ChallengeTimelineTemplateService.searchChallengeTimelineTemplates({ + typeId: challenge.typeId, + trackId: challenge.trackId, + isDefault: true, + }); + const challengeTimelineTemplate = supportedTemplates.result[0]; if (!challengeTimelineTemplate) { - throw new errors.BadRequestError(`The selected trackId ${challenge.trackId} and typeId: ${challenge.typeId} does not have a default timeline template. Please provide a timelineTemplateId`) + throw new errors.BadRequestError( + `The selected trackId ${challenge.trackId} and typeId: ${challenge.typeId} does not have a default timeline template. Please provide a timelineTemplateId` + ); } - challenge.timelineTemplateId = challengeTimelineTemplate.timelineTemplateId + challenge.timelineTemplateId = challengeTimelineTemplate.timelineTemplateId; } else { - throw new errors.BadRequestError(`trackId and typeId are required to create a challenge`) - } - } - - if (challenge.timelineTemplateId) { - if (!challenge.phases) { - challenge.phases = [] + throw new errors.BadRequestError(`trackId and typeId are required to create a challenge`); } - await phaseHelper.populatePhases(challenge.phases, challenge.startDate, challenge.timelineTemplateId) } + challenge.phases = await phaseHelper.populatePhasesForChallengeCreation( + challenge.phases, + challenge.startDate, + challenge.timelineTemplateId + ); // populate challenge terms // const projectTerms = await helper.getProjectDefaultTerms(challenge.projectId) // challenge.terms = await helper.validateChallengeTerms(_.union(projectTerms, challenge.terms)) // TODO - challenge terms returned from projects api don't have a role associated // this will need to be updated to associate project terms with a roleId - challenge.terms = await helper.validateChallengeTerms(challenge.terms || []) + challenge.terms = await helper.validateChallengeTerms(challenge.terms || []); // default the descriptionFormat if (!challenge.descriptionFormat) { - challenge.descriptionFormat = 'markdown' + challenge.descriptionFormat = "markdown"; } if (challenge.phases && challenge.phases.length > 0) { - challenge.endDate = helper.calculateChallengeEndDate(challenge) + challenge.endDate = helper.calculateChallengeEndDate(challenge); } - // auto-populate totalPrizes - if (challenge.prizeSets) { - const prizeSetsGroup = _.groupBy(challenge.prizeSets, 'type') - if (prizeSetsGroup[constants.prizeSetTypes.ChallengePrizes]) { - const totalPrizes = helper.sumOfPrizes(prizeSetsGroup[constants.prizeSetTypes.ChallengePrizes][0].prizes) - _.assign(challenge, { overview: { totalPrizes } }) - } - } + if (challenge.events == null) challenge.events = []; + if (challenge.attachments == null) challenge.attachments = []; + if (challenge.prizeSets == null) challenge.prizeSets = []; + if (challenge.metadata == null) challenge.metadata = []; + if (challenge.groups == null) challenge.groups = []; + if (challenge.tags == null) challenge.tags = []; + if (challenge.startDate != null) challenge.startDate = challenge.startDate; + if (challenge.endDate != null) challenge.endDate = challenge.endDate; + if (challenge.discussions == null) challenge.discussions = []; - const ret = await helper.create('Challenge', _.assign({ - id: uuid(), - created: moment().utc(), - createdBy: currentUser.handle || currentUser.sub, - updated: moment().utc(), - updatedBy: currentUser.handle || currentUser.sub - }, challenge)) - ret.numOfSubmissions = 0 - ret.numOfRegistrants = 0 - if (ret.phases && ret.phases.length > 0) { - const registrationPhase = _.find(ret.phases, p => p.name === 'Registration') - const submissionPhase = _.find(ret.phases, p => p.name === 'Submission') - ret.currentPhaseNames = _.map(_.filter(ret.phases, p => p.isOpen === true), 'name') - if (registrationPhase) { - ret.registrationStartDate = registrationPhase.actualStartDate || registrationPhase.scheduledStartDate - ret.registrationEndDate = registrationPhase.actualEndDate || registrationPhase.scheduledEndDate - } - if (submissionPhase) { - ret.submissionStartDate = submissionPhase.actualStartDate || submissionPhase.scheduledStartDate - ret.submissionEndDate = submissionPhase.actualEndDate || submissionPhase.scheduledEndDate - } - } + challenge.metadata = challenge.metadata.map((m) => ({ + name: m.name, + value: typeof m.value === "string" ? m.value : JSON.stringify(m.value), + })); - if (track) { - ret.track = track.name - } - if (type) { - ret.type = type.name - } + const grpcMetadata = new GrpcMetadata(); - // Create in ES - await esClient.create({ - index: config.get('ES.ES_INDEX'), - type: config.get('ES.ES_TYPE'), - refresh: config.get('ES.ES_REFRESH'), - id: ret.id, - body: ret - }) + grpcMetadata.set("handle", currentUser.handle); + grpcMetadata.set("userId", currentUser.userId); - // If the challenge is self-service, add the creating user as the "client manager", *not* the manager - // This is necessary for proper handling of the vanilla embed on the self-service work item dashboard + convertPrizeSetValuesToCents(challenge.prizeSets); + const ret = await challengeDomain.create(challenge, grpcMetadata); + convertPrizeSetValuesToDollars(ret.prizeSets, ret.overview); - if (challenge.legacy.selfService) { - if (currentUser.handle) { - await helper.createResource(ret.id, ret.createdBy, config.CLIENT_MANAGER_ROLE_ID) - } - } else { - // if created by a user, add user as a manager, but only if *not* a self-service challenge - if (currentUser.handle) { - // logger.debug(`Adding user as manager ${currentUser.handle}`) - await helper.createResource(ret.id, ret.createdBy, config.MANAGER_ROLE_ID) + ret.numOfSubmissions = 0; + ret.numOfRegistrants = 0; + + enrichChallengeForResponse(ret, track, type); + + const isLocal = process.env.LOCAL == "true"; + if (!isLocal) { + // Create in ES + await esClient.create({ + index: config.get("ES.ES_INDEX"), + type: config.get("ES.OPENSEARCH") == "false" ? config.get("ES.ES_TYPE") : undefined, + refresh: config.get("ES.ES_REFRESH"), + id: ret.id, + body: ret, + }); + + // If the challenge is self-service, add the creating user as the "client manager", *not* the manager + // This is necessary for proper handling of the vanilla embed on the self-service work item dashboard + + if (challenge.legacy.selfService) { + if (currentUser.handle) { + await helper.createResource(ret.id, ret.createdBy, config.CLIENT_MANAGER_ROLE_ID); + } } else { - // logger.debug(`Not adding manager ${currentUser.sub} ${JSON.stringify(currentUser)}`) + if (currentUser.handle) { + await helper.createResource(ret.id, ret.createdBy, config.MANAGER_ROLE_ID); + } } } // post bus event - await helper.postBusEvent(constants.Topics.ChallengeCreated, ret) - return ret -} + await helper.postBusEvent(constants.Topics.ChallengeCreated, ret); + return ret; +} createChallenge.schema = { currentUser: Joi.any(), - challenge: Joi.object().keys({ - typeId: Joi.id(), - trackId: Joi.id(), - legacy: Joi.object().keys({ - reviewType: Joi.string().valid(_.values(constants.reviewTypes)).insensitive().default(constants.reviewTypes.Internal), - confidentialityType: Joi.string().default(config.DEFAULT_CONFIDENTIALITY_TYPE), - forumId: Joi.number().integer(), - directProjectId: Joi.number().integer(), - screeningScorecardId: Joi.number().integer(), - reviewScorecardId: Joi.number().integer(), - isTask: Joi.boolean(), - useSchedulingAPI: Joi.boolean(), - pureV5Task: Joi.boolean(), - pureV5: Joi.boolean(), - selfService: Joi.boolean(), - selfServiceCopilot: Joi.string() - }), - billing: Joi.object().keys({ - billingAccountId: Joi.string(), - markup: Joi.number().min(0).max(100) - }).unknown(true), - task: Joi.object().keys({ - isTask: Joi.boolean().default(false), - isAssigned: Joi.boolean().default(false), - memberId: Joi.string().allow(null) - }), - name: Joi.string().required(), - description: Joi.string(), - privateDescription: Joi.string(), - descriptionFormat: Joi.string(), - metadata: Joi.array().items(Joi.object().keys({ - name: Joi.string().required(), - value: Joi.required() - })).unique((a, b) => a.name === b.name), - timelineTemplateId: Joi.string(), // Joi.optionalId(), - phases: Joi.array().items(Joi.object().keys({ - phaseId: Joi.id(), - duration: Joi.number().integer().min(0), - constraints: Joi.object().keys({ - name: Joi.string(), - value: Joi.number().integer().min(0) - }).optional() - })), - events: Joi.array().items(Joi.object().keys({ - id: Joi.number().required(), - name: Joi.string(), - key: Joi.string() - })), - discussions: Joi.array().items(Joi.object().keys({ - id: Joi.optionalId(), + challenge: Joi.object() + .keys({ + typeId: Joi.id(), + trackId: Joi.id(), + legacy: Joi.object().keys({ + reviewType: Joi.string() + .valid(_.values(constants.reviewTypes)) + .insensitive() + .default(constants.reviewTypes.Internal), + confidentialityType: Joi.string().default(config.DEFAULT_CONFIDENTIALITY_TYPE), + forumId: Joi.number().integer(), + directProjectId: Joi.number().integer(), + screeningScorecardId: Joi.number().integer(), + reviewScorecardId: Joi.number().integer(), + isTask: Joi.boolean(), + useSchedulingAPI: Joi.boolean(), + pureV5Task: Joi.boolean(), + pureV5: Joi.boolean(), + selfService: Joi.boolean(), + selfServiceCopilot: Joi.string(), + }), + billing: Joi.object() + .keys({ + billingAccountId: Joi.string(), + markup: Joi.number().min(0).max(100), + }) + .unknown(true), + task: Joi.object().keys({ + isTask: Joi.boolean().default(false), + isAssigned: Joi.boolean().default(false), + memberId: Joi.string().allow(null), + }), name: Joi.string().required(), - type: Joi.string().required().valid(_.values(constants.DiscussionTypes)), - provider: Joi.string().required(), - url: Joi.string(), - options: Joi.array().items(Joi.object()) - })), - prizeSets: Joi.array().items(Joi.object().keys({ - type: Joi.string().valid(_.values(constants.prizeSetTypes)).required(), description: Joi.string(), - prizes: Joi.array().items(Joi.object().keys({ - description: Joi.string(), - type: Joi.string().required(), - value: Joi.number().min(0).required() - })).min(1).required() - })), - tags: Joi.array().items(Joi.string()), // tag names - projectId: Joi.number().integer().positive(), - legacyId: Joi.number().integer().positive(), - startDate: Joi.date(), - status: Joi.string().valid(_.values(constants.challengeStatuses)), - groups: Joi.array().items(Joi.optionalId()).unique(), - // gitRepoURLs: Joi.array().items(Joi.string().uri()), - terms: Joi.array().items(Joi.object().keys({ - id: Joi.id(), - roleId: Joi.id() - })) - }).required(), - userToken: Joi.string().required() -} - + privateDescription: Joi.string(), + descriptionFormat: Joi.string(), + metadata: Joi.array() + .items( + Joi.object().keys({ + name: Joi.string().required(), + value: Joi.required(), + }) + ) + .unique((a, b) => a.name === b.name), + timelineTemplateId: Joi.string(), // Joi.optionalId(), + phases: Joi.array().items( + Joi.object().keys({ + phaseId: Joi.id(), + duration: Joi.number().integer().min(0), + constraints: Joi.array() + .items( + Joi.object() + .keys({ + name: Joi.string(), + value: Joi.number().integer().min(0), + }) + .optional() + ) + .optional(), + }) + ), + events: Joi.array().items( + Joi.object().keys({ + id: Joi.number().required(), + name: Joi.string(), + key: Joi.string(), + }) + ), + discussions: Joi.array().items( + Joi.object().keys({ + id: Joi.optionalId(), + name: Joi.string().required(), + type: Joi.string().required().valid(_.values(constants.DiscussionTypes)), + provider: Joi.string().required(), + url: Joi.string(), + options: Joi.array().items(Joi.object()), + }) + ), + prizeSets: Joi.array().items( + Joi.object().keys({ + type: Joi.string().valid(_.values(constants.prizeSetTypes)).required(), + description: Joi.string(), + prizes: Joi.array() + .items( + Joi.object().keys({ + description: Joi.string(), + type: Joi.string().required(), + value: Joi.number().min(0).required(), + }) + ) + .min(1) + .required(), + }) + ), + tags: Joi.array().items(Joi.string()), // tag names + projectId: Joi.number().integer().positive(), + legacyId: Joi.number().integer().positive(), + startDate: Joi.date().iso(), + status: Joi.string().valid(_.values(constants.challengeStatuses)), + groups: Joi.array().items(Joi.optionalId()).unique(), + // gitRepoURLs: Joi.array().items(Joi.string().uri()), + terms: Joi.array().items( + Joi.object().keys({ + id: Joi.id(), + roleId: Joi.id(), + }) + ), + }) + .required(), + userToken: Joi.string().required(), +}; /** * Populate phase data from phase API. * @param {Object} the challenge entity */ -async function getPhasesAndPopulate (data) { - _.each(data.phases, async p => { - const phase = await PhaseService.getPhase(p.phaseId) - p.name = phase.name +async function getPhasesAndPopulate(data) { + _.each(data.phases, async (p) => { + const phase = await PhaseService.getPhase(p.phaseId); + p.name = phase.name; if (phase.description) { - p.description = phase.description + p.description = phase.description; } - }) + }); } /** @@ -1184,31 +1295,39 @@ async function getPhasesAndPopulate (data) { * @param {Boolean} checkIfExists flag to check if challenge exists * @returns {Object} the challenge with given id */ -async function getChallenge (currentUser, id, checkIfExists) { +async function getChallenge(currentUser, id, checkIfExists) { // get challenge from Elasticsearch - let challenge + let challenge; // logger.warn(JSON.stringify({ // index: config.get('ES.ES_INDEX'), - // type: config.get('ES.ES_TYPE'), // _id: id // })) try { - challenge = await esClient.getSource({ - index: config.get('ES.ES_INDEX'), - type: config.get('ES.ES_TYPE'), - id - }) + if (config.get("ES.OPENSEARCH") == "true") { + challenge = ( + await esClient.getSource({ + index: config.get("ES.ES_INDEX"), + id, + }) + ).body; + } else { + challenge = await esClient.getSource({ + index: config.get("ES.ES_INDEX"), + type: config.get("ES.ES_TYPE"), + id, + }); + } } catch (e) { if (e.statusCode === HttpStatus.NOT_FOUND) { - throw new errors.NotFoundError(`Challenge of id ${id} is not found.`) + throw new errors.NotFoundError(`Challenge of id ${id} is not found.`); } else { - throw e + throw e; } } if (checkIfExists) { - return _.pick(challenge, ['id', 'legacyId']) + return _.pick(challenge, ["id", "legacyId"]); } - await helper.ensureUserCanViewChallenge(currentUser, challenge) + await helper.ensureUserCanViewChallenge(currentUser, challenge); // // FIXME: Temporarily hard coded as the migrad // // populate type property based on the typeId @@ -1226,38 +1345,43 @@ async function getChallenge (currentUser, id, checkIfExists) { // Remove privateDescription for unregistered users if (currentUser) { - if (!currentUser.isMachine && !helper.hasAdminRole(currentUser)) { - _.unset(challenge, 'billing') + if (!currentUser.isMachine && !hasAdminRole(currentUser)) { + _.unset(challenge, "billing"); if (_.isEmpty(challenge.privateDescription)) { - _.unset(challenge, 'privateDescription') - } else if (!_.get(challenge, 'task.isTask', false) || !_.get(challenge, 'task.isAssigned', false)) { - const memberResources = await helper.listResourcesByMemberAndChallenge(currentUser.userId, challenge.id) + _.unset(challenge, "privateDescription"); + } else if ( + !_.get(challenge, "task.isTask", false) || + !_.get(challenge, "task.isAssigned", false) + ) { + const memberResources = await helper.listResourcesByMemberAndChallenge( + currentUser.userId, + challenge.id + ); if (_.isEmpty(memberResources)) { - _.unset(challenge, 'privateDescription') + _.unset(challenge, "privateDescription"); } } } } else { - _.unset(challenge, 'billing') - _.unset(challenge, 'privateDescription') + _.unset(challenge, "billing"); + _.unset(challenge, "privateDescription"); } if (challenge.phases && challenge.phases.length > 0) { - await getPhasesAndPopulate(challenge) + await getPhasesAndPopulate(challenge); } if (challenge.status !== constants.challengeStatuses.Completed) { - _.unset(challenge, 'winners') + _.unset(challenge, "winners"); } - return challenge + return challenge; } - getChallenge.schema = { currentUser: Joi.any(), id: Joi.id(), - checkIfExists: Joi.boolean() -} + checkIfExists: Joi.boolean(), +}; /** * Get challenge statistics @@ -1265,42 +1389,47 @@ getChallenge.schema = { * @param {String} id the challenge id * @returns {Object} the challenge with given id */ -async function getChallengeStatistics (currentUser, id) { - const challenge = await getChallenge(currentUser, id) +async function getChallengeStatistics(currentUser, id) { + const challenge = await getChallenge(currentUser, id); // for now, only Data Science challenges are supported - if (challenge.type !== 'Challenge' && challenge.track !== 'Data Science') { - throw new errors.BadRequestError(`Challenge of type ${challenge.type} and track ${challenge.track} does not support statistics`) + if (challenge.type !== "Challenge" && challenge.track !== "Data Science") { + throw new errors.BadRequestError( + `Challenge of type ${challenge.type} and track ${challenge.track} does not support statistics` + ); } // get submissions - const submissions = await helper.getChallengeSubmissions(challenge.id) + const submissions = await helper.getChallengeSubmissions(challenge.id); // for each submission, load member profile - const map = {} + const map = {}; for (const submission of submissions) { if (!map[submission.memberId]) { // Load member profile and cache - const member = await helper.getMemberById(submission.memberId) + const member = await helper.getMemberById(submission.memberId); map[submission.memberId] = { photoUrl: member.photoURL, - rating: _.get(member, 'maxRating.rating', 0), - ratingColor: _.get(member, 'maxRating.ratingColor', '#9D9FA0'), + rating: _.get(member, "maxRating.rating", 0), + ratingColor: _.get(member, "maxRating.ratingColor", "#9D9FA0"), homeCountryCode: member.homeCountryCode, handle: member.handle, - submissions: [] - } + submissions: [], + }; } // add submission map[submission.memberId].submissions.push({ created: submission.created, - score: _.get(_.find(submission.review || [], r => r.metadata), 'score', 0) - }) - } - return _.map(_.keys(map), (userId) => map[userId]) + score: _.get( + _.find(submission.review || [], (r) => r.metadata), + "score", + 0 + ), + }); + } + return _.map(_.keys(map), (userId) => map[userId]); } - getChallengeStatistics.schema = { currentUser: Joi.any(), - id: Joi.id() -} + id: Joi.id(), +}; /** * Check whether given two PrizeSet Array are different. @@ -1308,8 +1437,8 @@ getChallengeStatistics.schema = { * @param {Array} otherPrizeSets the second PrizeSet Array * @returns {Boolean} true if different, false otherwise */ -function isDifferentPrizeSets (prizeSets = [], otherPrizeSets = []) { - return !_.isEqual(_.sortBy(prizeSets, 'type'), _.sortBy(otherPrizeSets, 'type')) +function isDifferentPrizeSets(prizeSets = [], otherPrizeSets = []) { + return !_.isEqual(_.sortBy(prizeSets, "type"), _.sortBy(otherPrizeSets, "type")); } /** @@ -1317,30 +1446,45 @@ function isDifferentPrizeSets (prizeSets = [], otherPrizeSets = []) { * @param {Array} winners the Winner Array * @param {String} winchallengeIdners the challenge ID */ -async function validateWinners (winners, challengeId) { - const challengeResources = await helper.getChallengeResources(challengeId) - const registrants = _.filter(challengeResources, r => r.roleId === config.SUBMITTER_ROLE_ID) +async function validateWinners(winners, challengeId) { + const challengeResources = await helper.getChallengeResources(challengeId); + const registrants = _.filter(challengeResources, (r) => r.roleId === config.SUBMITTER_ROLE_ID); for (const prizeType of _.values(constants.prizeSetTypes)) { - const filteredWinners = _.filter(winners, w => w.type === prizeType) + const filteredWinners = _.filter(winners, (w) => w.type === prizeType); for (const winner of filteredWinners) { - if (!_.find(registrants, r => _.toString(r.memberId) === _.toString(winner.userId))) { - throw new errors.BadRequestError(`Member with userId: ${winner.userId} is not registered on the challenge`) + if (!_.find(registrants, (r) => _.toString(r.memberId) === _.toString(winner.userId))) { + throw new errors.BadRequestError( + `Member with userId: ${winner.userId} is not registered on the challenge` + ); } - const diffWinners = _.differenceWith(filteredWinners, [winner], _.isEqual) + const diffWinners = _.differenceWith(filteredWinners, [winner], _.isEqual); if (diffWinners.length + 1 !== filteredWinners.length) { - throw new errors.BadRequestError(`Duplicate member with placement: ${helper.toString(winner)}`) + throw new errors.BadRequestError( + `Duplicate member with placement: ${helper.toString(winner)}` + ); } // find another member with the placement - const placementExists = _.find(diffWinners, function (w) { return w.placement === winner.placement }) - if (placementExists && (placementExists.userId !== winner.userId || placementExists.handle !== winner.handle)) { - throw new errors.BadRequestError(`Only one member can have a placement: ${winner.placement}`) + const placementExists = _.find(diffWinners, function (w) { + return w.placement === winner.placement; + }); + if ( + placementExists && + (placementExists.userId !== winner.userId || placementExists.handle !== winner.handle) + ) { + throw new errors.BadRequestError( + `Only one member can have a placement: ${winner.placement}` + ); } // find another placement for a member - const memberExists = _.find(diffWinners, function (w) { return w.userId === winner.userId && w.type === winner.type }) + const memberExists = _.find(diffWinners, function (w) { + return w.userId === winner.userId && w.type === winner.type; + }); if (memberExists && memberExists.placement !== winner.placement) { - throw new errors.BadRequestError(`The same member ${winner.userId} cannot have multiple placements`) + throw new errors.BadRequestError( + `The same member ${winner.userId} cannot have multiple placements` + ); } } } @@ -1354,660 +1498,636 @@ async function validateWinners (winners, challengeId) { * @param {Boolean} isFull the flag indicate it is a fully update operation. * @returns {Object} the updated challenge */ -async function update (currentUser, challengeId, data, isFull) { - const cancelReason = _.cloneDeep(data.cancelReason) - let sendActivationEmail = false - let sendSubmittedEmail = false - let sendCompletedEmail = false - let sendRejectedEmail = false - delete data.cancelReason - if (!_.isUndefined(_.get(data, 'legacy.reviewType'))) { - _.set(data, 'legacy.reviewType', _.toUpper(_.get(data, 'legacy.reviewType'))) - } - if (data.projectId) { - await helper.ensureProjectExist(data.projectId, currentUser) - } - - helper.ensureNoDuplicateOrNullElements(data.tags, 'tags') - helper.ensureNoDuplicateOrNullElements(data.groups, 'groups') - // helper.ensureNoDuplicateOrNullElements(data.gitRepoURLs, 'gitRepoURLs') - - const challenge = await helper.getById('Challenge', challengeId) - let dynamicDescription = _.cloneDeep(data.description || challenge.description) - if (challenge.legacy.selfService && data.metadata && data.metadata.length > 0) { - for (const entry of data.metadata) { - const regexp = new RegExp(`{{${entry.name}}}`, 'g') - dynamicDescription = dynamicDescription.replace(regexp, entry.value) - } - data.description = dynamicDescription +async function updateChallenge(currentUser, challengeId, data) { + const challenge = await challengeDomain.lookup(getLookupCriteria("id", challengeId)); + + // Remove fields from data that are not allowed to be updated and that match the existing challenge + data = sanitizeData(sanitizeChallenge(data), challenge); + console.debug("Sanitized Data:", data); + + validateChallengeUpdateRequest(currentUser, challenge, data); + + const projectId = _.get(challenge, "projectId"); + + let sendActivationEmail = false; + let sendSubmittedEmail = false; + let sendCompletedEmail = false; + let sendRejectedEmail = false; + + const { billingAccountId, markup } = await projectHelper.getProjectBillingInformation(projectId); + + if (billingAccountId && _.isUndefined(_.get(challenge, "billing.billingAccountId"))) { + _.set(data, "billing.billingAccountId", billingAccountId); + _.set(data, "billing.markup", markup || 0); } - if (challenge.legacy.selfService && data.status === constants.challengeStatuses.Draft && challenge.status !== constants.challengeStatuses.Draft) { - sendSubmittedEmail = true + + // Make sure the user cannot change the direct project ID + if (data.legacy && data.legacy.directProjectId) { + _.unset(data, "legacy.directProjectId"); } - // check if it's a self service challenge and project needs to be activated first - if (challenge.legacy.selfService && (data.status === constants.challengeStatuses.Approved || data.status === constants.challengeStatuses.Active) && challenge.status !== constants.challengeStatuses.Active) { - try { - const selfServiceProjectName = `Self service - ${challenge.createdBy} - ${challenge.name}` - const workItemSummary = _.get(_.find(_.get(challenge, 'metadata', []), m => m.name === 'websitePurpose.description'), 'value', 'N/A') - await helper.activateProject(challenge.projectId, currentUser, selfServiceProjectName, workItemSummary) - if (data.status === constants.challengeStatuses.Active) { - sendActivationEmail = true + + /* BEGIN self-service stuffs */ + + // TODO: At some point in the future this should be moved to a Self-Service Challenge Helper + + if (challenge.legacy.selfService) { + // prettier-ignore + sendSubmittedEmail = data.status === constants.challengeStatuses.Draft && challenge.status !== constants.challengeStatuses.Draft; + + if (data.metadata && data.metadata.length > 0) { + let dynamicDescription = _.cloneDeep(data.description || challenge.description); + for (const entry of data.metadata) { + const regexp = new RegExp(`{{${entry.name}}}`, "g"); + dynamicDescription = dynamicDescription.replace(regexp, entry.value); } - } catch (e) { - await update( - currentUser, - challengeId, - { - ...data, - status: constants.challengeStatuses.CancelledPaymentFailed, - cancelReason: `Failed to activate project. Error: ${e.message}. JSON: ${JSON.stringify(e)}` - }, - false - ) - throw new errors.BadRequestError('Failed to activate the challenge! The challenge has been canceled!') + data.description = dynamicDescription; } - } - const { billingAccountId, markup } = await helper.getProjectBillingInformation(_.get(challenge, 'projectId')) - if (billingAccountId && _.isUndefined(_.get(challenge, 'billing.billingAccountId'))) { - _.set(data, 'billing.billingAccountId', billingAccountId) - _.set(data, 'billing.markup', markup || 0) - } - if (billingAccountId && _.includes(config.TOPGEAR_BILLING_ACCOUNTS_ID, _.toString(billingAccountId))) { - if (_.isEmpty(data.metadata)) { - data.metadata = [] + // check if it's a self service challenge and project needs to be activated first + if ( + (data.status === constants.challengeStatuses.Approved || + data.status === constants.challengeStatuses.Active) && + challenge.status !== constants.challengeStatuses.Active + ) { + try { + const selfServiceProjectName = `Self service - ${challenge.createdBy} - ${challenge.name}`; + const workItemSummary = _.get( + _.find(_.get(challenge, "metadata", []), (m) => m.name === "websitePurpose.description"), + "value", + "N/A" + ); + await helper.activateProject( + projectId, + currentUser, + selfServiceProjectName, + workItemSummary + ); + + sendActivationEmail = data.status === constants.challengeStatuses.Active; + } catch (e) { + await updateChallenge( + currentUser, + challengeId, + { + ...data, + status: constants.challengeStatuses.CancelledPaymentFailed, + cancelReason: `Failed to activate project. Error: ${e.message}. JSON: ${JSON.stringify( + e + )}`, + }, + false + ); + throw new errors.BadRequestError( + "Failed to activate the challenge! The challenge has been canceled!" + ); + } } - if (!_.find(data.metadata, e => e.name === 'postMortemRequired')) { - data.metadata.push({ - name: 'postMortemRequired', - value: 'false' - }) + + if (data.status === constants.challengeStatuses.Draft) { + try { + await helper.updateSelfServiceProjectInfo( + projectId, + data.endDate || challenge.endDate, + currentUser + ); + } catch (e) { + logger.debug(`There was an error trying to update the project: ${e.message}`); + } } } + + /* END self-service stuffs */ + + let isChallengeBeingActivated = false; if (data.status) { if (data.status === constants.challengeStatuses.Active) { - if (!_.get(challenge, 'legacy.pureV5Task') && !_.get(challenge, 'legacy.pureV5') && _.isUndefined(_.get(challenge, 'legacyId'))) { - throw new errors.BadRequestError('You cannot activate the challenge as it has not been created on legacy yet. Please try again later or contact support.') + if ( + !_.get(challenge, "legacy.pureV5Task") && + !_.get(challenge, "legacy.pureV5") && + _.isUndefined(_.get(challenge, "legacyId")) + ) { + throw new errors.BadRequestError( + "You cannot activate the challenge as it has not been created on legacy yet. Please try again later or contact support." + ); } // if activating a challenge, the challenge must have a billing account id - if ((!billingAccountId || billingAccountId === null) && - challenge.status === constants.challengeStatuses.Draft) { - throw new errors.BadRequestError('Cannot Activate this project, it has no active billing account.') + if ( + (!billingAccountId || billingAccountId === null) && + challenge.status === constants.challengeStatuses.Draft + ) { + throw new errors.BadRequestError( + "Cannot Activate this project, it has no active billing account." + ); + } + if (challenge.status === constants.challengeStatuses.Draft) { + isChallengeBeingActivated = true; } } - if (data.status === constants.challengeStatuses.CancelledRequirementsInfeasible || data.status === constants.challengeStatuses.CancelledPaymentFailed) { + + if ( + data.status === constants.challengeStatuses.CancelledRequirementsInfeasible || + data.status === constants.challengeStatuses.CancelledPaymentFailed + ) { try { - await helper.cancelProject(challenge.projectId, cancelReason, currentUser) + await helper.cancelProject(challenge.projectId, cancelReason, currentUser); } catch (e) { - logger.debug(`There was an error trying to cancel the project: ${e.message}`) + logger.debug(`There was an error trying to cancel the project: ${e.message}`); } - sendRejectedEmail = true + sendRejectedEmail = true; } + if (data.status === constants.challengeStatuses.Completed) { - if (!_.get(challenge, 'legacy.pureV5Task') && !_.get(challenge, 'legacy.pureV5') && challenge.status !== constants.challengeStatuses.Active) { - throw new errors.BadRequestError('You cannot mark a Draft challenge as Completed') + if ( + !_.get(challenge, "legacy.pureV5Task") && + !_.get(challenge, "legacy.pureV5") && + challenge.status !== constants.challengeStatuses.Active + ) { + throw new errors.BadRequestError("You cannot mark a Draft challenge as Completed"); } - sendCompletedEmail = true + sendCompletedEmail = true; } } - // FIXME: Tech Debt - if (_.get(challenge, 'legacy.track') && _.get(data, 'legacy.track') && _.get(challenge, 'legacy.track') !== _.get(data, 'legacy.track')) { - throw new errors.ForbiddenError('Cannot change legacy.track') - } - if (_.get(challenge, 'trackId') && _.get(data, 'trackId') && _.get(challenge, 'trackId') !== _.get(data, 'trackId')) { - throw new errors.ForbiddenError('Cannot change trackId') - } - if (_.get(challenge, 'typeId') && _.get(data, 'typeId') && _.get(challenge, 'typeId') !== _.get(data, 'typeId')) { - throw new errors.ForbiddenError('Cannot change typeId') - } - if (_.get(challenge, 'legacy.useSchedulingAPI') && _.get(data, 'legacy.useSchedulingAPI') && _.get(challenge, 'legacy.useSchedulingAPI') !== _.get(data, 'legacy.useSchedulingAPI')) { - throw new errors.ForbiddenError('Cannot change legacy.useSchedulingAPI') - } - if (_.get(challenge, 'legacy.pureV5Task') && _.get(data, 'legacy.pureV5Task') && _.get(challenge, 'legacy.pureV5Task') !== _.get(data, 'legacy.pureV5Task')) { - throw new errors.ForbiddenError('Cannot change legacy.pureV5Task') - } - if (_.get(challenge, 'legacy.pureV5') && _.get(data, 'legacy.pureV5') && _.get(challenge, 'legacy.pureV5') !== _.get(data, 'legacy.pureV5')) { - throw new errors.ForbiddenError('Cannot change legacy.pureV5') - } - if (_.get(challenge, 'legacy.selfService') && _.get(data, 'legacy.selfService') && _.get(challenge, 'legacy.selfService') !== _.get(data, 'legacy.selfService')) { - throw new errors.ForbiddenError('Cannot change legacy.selfService') - } - - if (!_.isUndefined(challenge.legacy) && !_.isUndefined(data.legacy)) { - _.extend(challenge.legacy, data.legacy) - } - - if (!_.isUndefined(challenge.billing) && !_.isUndefined(data.billing)) { - _.extend(challenge.billing, data.billing) - } else if (_.isUndefined(challenge.billing) && !_.isUndefined(data.billing)) { - challenge.billing = data.billing - } - - await helper.ensureUserCanModifyChallenge(currentUser, challenge) - - // check groups access to be updated group values - if (data.groups) { - await ensureAcessibilityToModifiedGroups(currentUser, data, challenge) - } - let newAttachments - if (isFull || !_.isUndefined(data.attachments)) { - newAttachments = data.attachments - } - - await ensureAccessibleForChallenge(currentUser, challenge) - // Only M2M can update url and options of discussions if (data.discussions && data.discussions.length > 0) { if (challenge.discussions && challenge.discussions.length > 0) { for (let i = 0; i < data.discussions.length; i += 1) { if (_.isUndefined(data.discussions[i].id)) { - data.discussions[i].id = uuid() + data.discussions[i].id = uuid(); if (!currentUser.isMachine) { - _.unset(data.discussions, 'url') - _.unset(data.discussions, 'options') + _.unset(data.discussions, "url"); + _.unset(data.discussions, "options"); } } else if (!currentUser.isMachine) { - const existingDiscussion = _.find(_.get(challenge, 'discussions', []), d => d.id === data.discussions[i].id) + const existingDiscussion = _.find( + _.get(challenge, "discussions", []), + (d) => d.id === data.discussions[i].id + ); if (existingDiscussion) { - _.assign(data.discussions[i], _.pick(existingDiscussion, ['url', 'options'])) + _.assign(data.discussions[i], _.pick(existingDiscussion, ["url", "options"])); } else { - _.unset(data.discussions, 'url') - _.unset(data.discussions, 'options') + _.unset(data.discussions, "url"); + _.unset(data.discussions, "options"); } } } } else { for (let i = 0; i < data.discussions.length; i += 1) { - data.discussions[i].id = uuid() - data.discussions[i].name = data.discussions[i].name.substring(0, config.FORUM_TITLE_LENGTH_LIMIT) + data.discussions[i].id = uuid(); + data.discussions[i].name = data.discussions[i].name.substring( + 0, + config.FORUM_TITLE_LENGTH_LIMIT + ); } } } - // Validate the challenge terms - let newTermsOfUse - if (!_.isUndefined(data.terms)) { - // helper.ensureNoDuplicateOrNullElements(data.terms, 'terms') - - // Get the project default terms - const defaultTerms = await helper.getProjectDefaultTerms(challenge.projectId) - - if (defaultTerms) { - // Make sure that the default project terms were not removed - // TODO - there are no default terms returned by v5 - // the terms array is objects with a roleId now, so this _.difference won't work - // const removedTerms = _.difference(defaultTerms, data.terms) - // if (removedTerms.length !== 0) { - // throw new errors.BadRequestError(`Default project terms ${removedTerms} should not be removed`) - // } - } - // newTermsOfUse = await helper.validateChallengeTerms(_.union(data.terms, defaultTerms)) - newTermsOfUse = await helper.validateChallengeTerms(data.terms) - } - - await validateChallengeData(data) - if ((challenge.status === constants.challengeStatuses.Completed || challenge.status === constants.challengeStatuses.Cancelled) && data.status && (data.status !== challenge.status && data.status !== constants.challengeStatuses.CancelledClientRequest)) { - throw new errors.BadRequestError(`Cannot change ${challenge.status} challenge status to ${data.status} status`) - } - - if (data.winners && data.winners.length > 0 && (challenge.status !== constants.challengeStatuses.Completed && data.status !== constants.challengeStatuses.Completed)) { - throw new errors.BadRequestError(`Cannot set winners for challenge with non-completed ${challenge.status} status`) - } - // TODO: Fix this Tech Debt once legacy is turned off - const finalStatus = data.status || challenge.status - const finalTimelineTemplateId = data.timelineTemplateId || challenge.timelineTemplateId - if (!_.get(data, 'legacy.pureV5') && !_.get(challenge, 'legacy.pureV5')) { - if (finalStatus !== constants.challengeStatuses.New && finalTimelineTemplateId !== challenge.timelineTemplateId) { - throw new errors.BadRequestError(`Cannot change the timelineTemplateId for challenges with status: ${finalStatus}`) + const finalStatus = data.status || challenge.status; + const finalTimelineTemplateId = data.timelineTemplateId || challenge.timelineTemplateId; + const timelineTemplateChanged = false; + if (!_.get(data, "legacy.pureV5") && !_.get(challenge, "legacy.pureV5")) { + if ( + finalStatus !== constants.challengeStatuses.New && + finalTimelineTemplateId !== challenge.timelineTemplateId + ) { + throw new errors.BadRequestError( + `Cannot change the timelineTemplateId for challenges with status: ${finalStatus}` + ); } } else if (finalTimelineTemplateId !== challenge.timelineTemplateId) { // make sure there are no previous phases if the timeline template has changed - challenge.phases = [] - } - - if (data.prizeSets) { - if (isDifferentPrizeSets(data.prizeSets, challenge.prizeSets) && finalStatus === constants.challengeStatuses.Completed) { - throw new errors.BadRequestError(`Cannot update prizeSets for challenges with status: ${finalStatus}!`) - } - const prizeSetsGroup = _.groupBy(data.prizeSets, 'type') - if (!prizeSetsGroup[constants.prizeSetTypes.ChallengePrizes] && _.get(challenge, 'overview.totalPrizes')) { + challenge.phases = []; + timelineTemplateChanged = true; + } + + if (data.prizeSets && data.prizeSets.length > 0) { + if ( + isDifferentPrizeSets(data.prizeSets, challenge.prizeSets) && + finalStatus === constants.challengeStatuses.Completed + ) { + throw new errors.BadRequestError( + `Cannot update prizeSets for challenges with status: ${finalStatus}!` + ); + } + const prizeSetsGroup = _.groupBy(data.prizeSets, "type"); + if ( + !prizeSetsGroup[constants.prizeSetTypes.ChallengePrizes] && + _.get(challenge, "overview.totalPrizes") + ) { // remove the totalPrizes if challenge prizes are empty - challenge.overview = _.omit(challenge.overview, ['totalPrizes']) + data.overview = challenge.overview = _.omit(challenge.overview, ["totalPrizes"]); } else { - const totalPrizes = helper.sumOfPrizes(prizeSetsGroup[constants.prizeSetTypes.ChallengePrizes][0].prizes) - logger.debug(`re-calculate total prizes, current value is ${totalPrizes.value}`) - _.assign(challenge, { overview: { totalPrizes } }) - } - } - - if (data.phases || data.startDate) { - if (challenge.status === constants.challengeStatuses.Completed || challenge.status.indexOf(constants.challengeStatuses.Cancelled) > -1) { - throw new BadRequestError(`Challenge phase/start date can not be modified for Completed or Cancelled challenges.`) - } - - if (data.phases && data.phases.length > 0) { - for (let i = 0; i < challenge.phases.length; i += 1) { - const updatedPhaseInfo = _.find(data.phases, p => p.phaseId === challenge.phases[i].phaseId) - if (updatedPhaseInfo) { - _.extend(challenge.phases[i], updatedPhaseInfo) - } - } - if (challenge.phases.length === 0 && data.phases && data.phases.length > 0) { - challenge.phases = data.phases - } - } - - const newPhases = _.cloneDeep(challenge.phases) || [] - const newStartDate = data.startDate || challenge.startDate - - await phaseHelper.validatePhases(newPhases) - // populate phases - - await phaseHelper.populatePhases(newPhases, newStartDate, data.timelineTemplateId || challenge.timelineTemplateId) - data.phases = newPhases - challenge.phases = newPhases - data.startDate = newStartDate - data.endDate = helper.calculateChallengeEndDate(challenge, data) - } - - // PUT HERE - if (data.status) { - if (challenge.legacy.selfService && data.status === constants.challengeStatuses.Draft) { - try { - await helper.updateSelfServiceProjectInfo(challenge.projectId, data.endDate || challenge.endDate, currentUser) - } catch (e) { - logger.debug(`There was an error trying to update the project: ${e.message}`) - } - } + const totalPrizes = helper.sumOfPrizes( + prizeSetsGroup[constants.prizeSetTypes.ChallengePrizes][0].prizes + ); + _.assign(challenge, { overview: { totalPrizes } }); + _.assign(data, { overview: { totalPrizes } }); + } + } + + if (data.phases || data.startDate || timelineTemplateChanged) { + if ( + challenge.status === constants.challengeStatuses.Completed || + challenge.status.indexOf(constants.challengeStatuses.Cancelled) > -1 + ) { + throw new BadRequestError( + `Challenge phase/start date can not be modified for Completed or Cancelled challenges.` + ); + } + const newStartDate = data.startDate || challenge.startDate; + let newPhases; + if (timelineTemplateChanged) { + newPhases = await phaseHelper.populatePhasesForChallengeCreation( + data.phases, + newStartDate, + finalTimelineTemplateId + ); + } else if (data.startDate || (data.phases && data.phases.length > 0)) { + newPhases = await phaseHelper.populatePhasesForChallengeUpdate( + challenge.phases, + data.phases, + challenge.timelineTemplateId, + isChallengeBeingActivated + ); + } + + data.phases = newPhases; + data.startDate = new Date(newStartDate).toISOString(); + data.endDate = helper.calculateChallengeEndDate(challenge, data); } if (data.winners && data.winners.length && data.winners.length > 0) { - await validateWinners(data.winners, challengeId) + console.log("Request to validate winners", data.winners, challengeId); + await validateWinners(data.winners, challengeId); } // Only m2m tokens are allowed to modify the `task.*` information on a challenge - if (!_.isUndefined(_.get(data, 'task')) && !currentUser.isMachine) { - if (!_.isUndefined(_.get(challenge, 'task'))) { - logger.info(`User ${currentUser.handle || currentUser.sub} is not allowed to modify the task information on challenge ${challengeId}`) - data.task = challenge.task - logger.info(`Task information on challenge ${challengeId} is reset to ${JSON.stringify(challenge.task)}. Original data: ${JSON.stringify(data.task)}`) + if (!_.isUndefined(_.get(data, "task")) && !currentUser.isMachine) { + if (!_.isUndefined(_.get(challenge, "task"))) { + logger.info( + `User ${ + currentUser.handle || currentUser.sub + } is not allowed to modify the task information on challenge ${challengeId}` + ); + data.task = challenge.task; + logger.info( + `Task information on challenge ${challengeId} is reset to ${JSON.stringify( + challenge.task + )}. Original data: ${JSON.stringify(data.task)}` + ); } else { - delete data.task + delete data.task; } } // task.memberId goes out of sync due to another processor setting "task.memberId" but subsequent immediate update to the task // will not have the memberId set. So we need to set it using winners to ensure it is always in sync. The proper fix is to correct // the sync issue in the processor. However this is quick fix that works since winner.userId is task.memberId. - if (_.get(challenge, 'legacy.pureV5Task') && !_.isUndefined(data.winners)) { - const winnerMemberId = _.get(data.winners, '[0].userId') - logger.info(`Setting task.memberId to ${winnerMemberId} for challenge ${challengeId}. Task ${_.get(data, 'task')} - ${_.get(challenge, 'task')}`) - - if (winnerMemberId != null && _.get(data, 'task.memberId') !== winnerMemberId) { - logger.info(`Task ${challengeId} has a winner ${winnerMemberId}`) + if (_.get(challenge, "legacy.pureV5Task") && !_.isUndefined(data.winners)) { + const winnerMemberId = _.get(data.winners, "[0].userId"); + logger.info( + `Setting task.memberId to ${winnerMemberId} for challenge ${challengeId}. Task ${_.get( + data, + "task" + )} - ${_.get(challenge, "task")}` + ); + + if (winnerMemberId != null && _.get(data, "task.memberId") !== winnerMemberId) { + logger.info(`Task ${challengeId} has a winner ${winnerMemberId}`); data.task = { isTask: true, isAssigned: true, - memberId: winnerMemberId - } - logger.warn(`task.memberId mismatched with winner memberId. task.memberId is updated to ${winnerMemberId}`) + memberId: winnerMemberId, + }; + logger.warn( + `task.memberId mismatched with winner memberId. task.memberId is updated to ${winnerMemberId}` + ); } else { - logger.info(`task ${challengeId} has no winner set yet.`) + logger.info(`task ${challengeId} has no winner set yet.`); } } else { - logger.info(`${challengeId} is not a pureV5 challenge or has no winners set yet.`) - } - - data.updated = moment().utc() - data.updatedBy = currentUser.handle || currentUser.sub - const finalMetadata = [...challenge.metadata || []] - _.each(data.metadata || [], (rec) => { - const existingMeta = _.findIndex(finalMetadata, m => m.name === rec.name) - if (existingMeta > -1) { - finalMetadata[existingMeta].value = rec.value - } else { - finalMetadata.push(rec) - } - }) - data.metadata = finalMetadata - const updateDetails = {} - const auditLogs = [] - let phasesHaveBeenModified = false - _.each(data, (value, key) => { - let op - if (key === 'metadata') { - if (_.isUndefined(challenge[key]) || challenge[key].length !== value.length || - _.differenceWith(challenge[key], value, _.isEqual).length !== 0) { - op = '$PUT' - } - } else if (key === 'phases') { - // always consider a modification if the property exists - phasesHaveBeenModified = true - logger.info('update phases') - op = '$PUT' - } else if (key === 'prizeSets') { - if (isDifferentPrizeSets(challenge[key], value)) { - logger.info('update prize sets') - op = '$PUT' - } - } else if (key === 'tags') { - if (_.isUndefined(challenge[key]) || challenge[key].length !== value.length || - _.intersection(challenge[key], value).length !== value.length) { - op = '$PUT' - } - } else if (key === 'attachments') { - const oldIds = _.map(challenge.attachments || [], (a) => a.id) - if (oldIds.length !== value.length || - _.intersection(oldIds, _.map(value, a => a.id)).length !== value.length) { - op = '$PUT' - } - } else if (key === 'groups') { - if (_.isUndefined(challenge[key]) || challenge[key].length !== value.length || - _.intersection(challenge[key], value).length !== value.length) { - op = '$PUT' - } - // } else if (key === 'gitRepoURLs') { - // if (_.isUndefined(challenge[key]) || challenge[key].length !== value.length || - // _.intersection(challenge[key], value).length !== value.length) { - // op = '$PUT' - // } - } else if (key === 'winners') { - if (_.isUndefined(challenge[key]) || challenge[key].length !== value.length || - _.intersectionWith(challenge[key], value, _.isEqual).length !== value.length) { - op = '$PUT' - } - } else if (key === 'terms') { - const oldIds = _.map(challenge.terms || [], (t) => t.id) - const newIds = _.map(value || [], (t) => t.id) - if (oldIds.length !== newIds.length || - _.intersection(oldIds, newIds).length !== value.length) { - op = '$PUT' - } - } else if (key === 'billing' || key === 'legacy') { - // make sure that's always being udpated - op = '$PUT' - } else if (_.isUndefined(challenge[key]) || challenge[key] !== value) { - op = '$PUT' - } else if (_.get(challenge, 'legacy.pureV5Task') && key === 'task') { - // always update task for pureV5 challenges - op = '$PUT' - } - - if (op) { - if (_.isUndefined(updateDetails[op])) { - updateDetails[op] = {} - } - if (key === 'attachments') { - updateDetails[op].attachments = newAttachments - } else if (key === 'terms') { - updateDetails[op].terms = newTermsOfUse - } else { - updateDetails[op][key] = value - } - if (key !== 'updated' && key !== 'updatedBy') { - let oldValue - let newValue - if (key === 'attachments') { - oldValue = challenge.attachments ? JSON.stringify(challenge.attachments) : 'NULL' - newValue = JSON.stringify(newAttachments) - } else if (key === 'terms') { - oldValue = challenge.terms ? JSON.stringify(challenge.terms) : 'NULL' - newValue = JSON.stringify(newTermsOfUse) - } else { - oldValue = challenge[key] ? JSON.stringify(challenge[key]) : 'NULL' - newValue = JSON.stringify(value) - } - // logger.debug(`Audit Log: Key ${key} OldValue: ${oldValue} NewValue: ${newValue}`) - auditLogs.push({ - id: uuid(), - challengeId, - fieldName: key, - oldValue, - newValue, - created: moment().utc(), - createdBy: currentUser.handle || currentUser.sub, - memberId: currentUser.userId || null - }) + logger.info(`${challengeId} is not a pureV5 challenge or has no winners set yet.`); + } + + const { track, type } = await challengeHelper.validateAndGetChallengeTypeAndTrack({ + typeId: challenge.typeId, + trackId: challenge.trackId, + timelineTemplateId: challenge.timelineTemplateId, + }); + + if (_.get(type, "isTask")) { + if (!_.isEmpty(_.get(data, "task.memberId"))) { + const challengeResources = await helper.getChallengeResources(challengeId); + const registrants = _.filter( + challengeResources, + (r) => r.roleId === config.SUBMITTER_ROLE_ID + ); + if ( + !_.find( + registrants, + (r) => _.toString(r.memberId) === _.toString(_.get(data, "task.memberId")) + ) + ) { + throw new errors.BadRequestError( + `Member ${_.get( + data, + "task.memberId" + )} is not a submitter resource of challenge ${challengeId}` + ); } } - }) - - if (isFull && _.isUndefined(data.metadata) && challenge.metadata) { - updateDetails['$DELETE'] = { metadata: null } - auditLogs.push({ - id: uuid(), - challengeId, - fieldName: 'metadata', - oldValue: JSON.stringify(challenge.metadata), - newValue: 'NULL', - created: moment().utc(), - createdBy: currentUser.handle || currentUser.sub, - memberId: currentUser.userId || null - }) - delete challenge.metadata - // send null to Elasticsearch to clear the field - data.metadata = null - } - if (isFull && _.isUndefined(data.attachments) && challenge.attachments) { - if (!updateDetails['$DELETE']) { - updateDetails['$DELETE'] = {} - } - updateDetails['$DELETE'].attachments = null - auditLogs.push({ - id: uuid(), - challengeId, - fieldName: 'attachments', - oldValue: JSON.stringify(challenge.attachments), - newValue: 'NULL', - created: moment().utc(), - createdBy: currentUser.handle || currentUser.sub, - memberId: currentUser.userId || null - }) - delete challenge.attachments - // send null to Elasticsearch to clear the field - data.attachments = null - } - if (isFull && _.isUndefined(data.groups) && challenge.groups) { - if (!updateDetails['$DELETE']) { - updateDetails['$DELETE'] = {} - } - updateDetails['$DELETE'].groups = null - auditLogs.push({ - id: uuid(), - challengeId, - fieldName: 'groups', - oldValue: JSON.stringify(challenge.groups), - newValue: 'NULL', - created: moment().utc(), - createdBy: currentUser.handle || currentUser.sub, - memberId: currentUser.userId || null - }) - delete challenge.groups - // send null to Elasticsearch to clear the field - data.groups = null - } - // if (isFull && _.isUndefined(data.gitRepoURLs) && challenge.gitRepoURLs) { - // if (!updateDetails['$DELETE']) { - // updateDetails['$DELETE'] = {} - // } - // updateDetails['$DELETE'].gitRepoURLs = null - // auditLogs.push({ - // id: uuid(), - // challengeId, - // fieldName: 'gitRepoURLs', - // oldValue: JSON.stringify(challenge.gitRepoURLs), - // newValue: 'NULL', - // created: moment().utc(), - // createdBy: currentUser.handle || currentUser.sub, - // memberId: currentUser.userId || null - // }) - // delete challenge.gitRepoURLs - // // send null to Elasticsearch to clear the field - // data.gitRepoURLs = null - // } - if (isFull && _.isUndefined(data.legacyId) && challenge.legacyId) { - data.legacyId = challenge.legacyId } - if (isFull && _.isUndefined(data.winners) && challenge.winners) { - if (!updateDetails['$DELETE']) { - updateDetails['$DELETE'] = {} - } - updateDetails['$DELETE'].winners = null - auditLogs.push({ - id: uuid(), - challengeId, - fieldName: 'winners', - oldValue: JSON.stringify(challenge.winners), - newValue: 'NULL', - created: moment().utc(), - createdBy: currentUser.handle || currentUser.sub, - memberId: currentUser.userId || null - }) - delete challenge.winners - // send null to Elasticsearch to clear the field - data.winners = null + + if (!_.isUndefined(data.terms)) { + await helper.validateChallengeTerms(data.terms.map((t) => t.id)); } - const { track, type } = await validateChallengeData(_.pick(challenge, ['trackId', 'typeId'])) + if (data.phases && data.phases.length > 0) { + await getPhasesAndPopulate(data); - if (_.get(type, 'isTask')) { - if (!_.isEmpty(_.get(data, 'task.memberId'))) { - const challengeResources = await helper.getChallengeResources(challengeId) - const registrants = _.filter(challengeResources, r => r.roleId === config.SUBMITTER_ROLE_ID) - if (!_.find(registrants, r => _.toString(r.memberId) === _.toString(_.get(data, 'task.memberId')))) { - throw new errors.BadRequestError(`Member ${_.get(data, 'task.memberId')} is not a submitter resource of challenge ${challengeId}`) - } + if (deepEqual(data.phases, challenge.phases)) { + delete data.phases; } } - logger.debug(`Challenge.update id: ${challengeId} Details: ${JSON.stringify(updateDetails)}`) - await models.Challenge.update({ id: challengeId }, updateDetails) - - if (auditLogs.length > 0) { - await models.AuditLog.batchPut(auditLogs) - } + try { + const updateInput = sanitizeRepeatedFieldsInUpdateRequest(data); - delete data.attachments - delete data.terms - _.assign(challenge, data) - if (!_.isUndefined(newAttachments)) { - challenge.attachments = newAttachments - data.attachments = newAttachments - } + if (!_.isEmpty(updateInput)) { + const grpcMetadata = new GrpcMetadata(); - if (!_.isUndefined(newTermsOfUse)) { - challenge.terms = newTermsOfUse - data.terms = newTermsOfUse - } + grpcMetadata.set("handle", currentUser.handle); + grpcMetadata.set("userId", currentUser.userId); - if (challenge.phases && challenge.phases.length > 0) { - await getPhasesAndPopulate(challenge) + if (updateInput.prizeSetUpdate != null) { + convertPrizeSetValuesToCents(updateInput.prizeSetUpdate.prizeSets); + } + await challengeDomain.update( + { + filterCriteria: getScanCriteria({ id: challengeId }), + updateInput, + }, + grpcMetadata + ); + } + } catch (e) { + throw e; } - // Populate challenge.track and challenge.type based on the track/type IDs - - if (track) { - challenge.track = track.name - } - if (type) { - challenge.type = type.name - } + const updatedChallenge = await challengeDomain.lookup(getLookupCriteria("id", challengeId)); + convertPrizeSetValuesToDollars(updatedChallenge.prizeSets, updatedChallenge.overview); // post bus event - logger.debug(`Post Bus Event: ${constants.Topics.ChallengeUpdated} ${JSON.stringify(challenge)}`) - const options = {} - if (challenge.status === 'Completed') { - options.key = `${challenge.id}:${challenge.status}` - } - await helper.postBusEvent(constants.Topics.ChallengeUpdated, challenge, options) - if (phasesHaveBeenModified === true && _.get(challenge, 'legacy.useSchedulingAPI')) { - await helper.postBusEvent(config.SCHEDULING_TOPIC, { id: challengeId }) - } - if (challenge.phases && challenge.phases.length > 0) { - challenge.currentPhase = challenge.phases.slice().reverse().find(phase => phase.isOpen) - challenge.endDate = helper.calculateChallengeEndDate(challenge) - const registrationPhase = _.find(challenge.phases, p => p.name === 'Registration') - const submissionPhase = _.find(challenge.phases, p => p.name === 'Submission') - challenge.currentPhaseNames = _.map(_.filter(challenge.phases, p => p.isOpen === true), 'name') - if (registrationPhase) { - challenge.registrationStartDate = registrationPhase.actualStartDate || registrationPhase.scheduledStartDate - challenge.registrationEndDate = registrationPhase.actualEndDate || registrationPhase.scheduledEndDate - } - if (submissionPhase) { - challenge.submissionStartDate = submissionPhase.actualStartDate || submissionPhase.scheduledStartDate - challenge.submissionEndDate = submissionPhase.actualEndDate || submissionPhase.scheduledEndDate + logger.debug( + `Post Bus Event: ${constants.Topics.ChallengeUpdated} ${JSON.stringify(updatedChallenge)}` + ); + + enrichChallengeForResponse(updatedChallenge, track, type); + + await helper.postBusEvent(constants.Topics.ChallengeUpdated, updatedChallenge, { + key: + updatedChallenge.status === "Completed" + ? `${updatedChallenge.id}:${updatedChallenge.status}` + : undefined, + }); + + const isLocal = process.env.LOCAL == "true"; + if (!isLocal) { + // Update ES + await esClient.update({ + index: config.get("ES.ES_INDEX"), + type: config.get("ES.OPENSEARCH") == "false" ? config.get("ES.ES_TYPE") : undefined, + refresh: config.get("ES.ES_REFRESH"), + id: challengeId, + body: { + doc: updatedChallenge, + }, + }); + + if (updatedChallenge.legacy.selfService) { + const creator = await helper.getMemberByHandle(updatedChallenge.createdBy); + if (sendSubmittedEmail) { + await helper.sendSelfServiceNotification( + constants.SelfServiceNotificationTypes.WORK_REQUEST_SUBMITTED, + [{ email: creator.email }], + { + handle: creator.handle, + workItemName: updatedChallenge.name, + } + ); + } + if (sendActivationEmail) { + await helper.sendSelfServiceNotification( + constants.SelfServiceNotificationTypes.WORK_REQUEST_STARTED, + [{ email: creator.email }], + { + handle: creator.handle, + workItemName: updatedChallenge.name, + workItemUrl: `${config.SELF_SERVICE_APP_URL}/work-items/${updatedChallenge.id}`, + } + ); + } + if (sendCompletedEmail) { + await helper.sendSelfServiceNotification( + constants.SelfServiceNotificationTypes.WORK_COMPLETED, + [{ email: creator.email }], + { + handle: creator.handle, + workItemName: updatedChallenge.name, + workItemUrl: `${config.SELF_SERVICE_APP_URL}/work-items/${updatedChallenge.id}?tab=solutions`, + } + ); + } + if (sendRejectedEmail || cancelReason) { + logger.debug("Should send redirected email"); + await helper.sendSelfServiceNotification( + constants.SelfServiceNotificationTypes.WORK_REQUEST_REDIRECTED, + [{ email: creator.email }], + { + handle: creator.handle, + workItemName: updatedChallenge.name, + } + ); + } } } - // Update ES - await esClient.update({ - index: config.get('ES.ES_INDEX'), - type: config.get('ES.ES_TYPE'), - refresh: config.get('ES.ES_REFRESH'), - id: challengeId, - body: { - doc: challenge - } - }) - if (challenge.legacy.selfService) { - const creator = await helper.getMemberByHandle(challenge.createdBy) - if (sendSubmittedEmail) { - await helper.sendSelfServiceNotification( - constants.SelfServiceNotificationTypes.WORK_REQUEST_SUBMITTED, - [{ email: creator.email }], - { - handle: creator.handle, - workItemName: challenge.name - } - ) - } - if (sendActivationEmail) { - await helper.sendSelfServiceNotification( - constants.SelfServiceNotificationTypes.WORK_REQUEST_STARTED, - [{ email: creator.email }], - { - handle: creator.handle, - workItemName: challenge.name, - workItemUrl: `${config.SELF_SERVICE_APP_URL}/work-items/${challenge.id}` - } - ) - } - if (sendCompletedEmail) { - await helper.sendSelfServiceNotification( - constants.SelfServiceNotificationTypes.WORK_COMPLETED, - [{ email: creator.email }], - { - handle: creator.handle, - workItemName: challenge.name, - workItemUrl: `${config.SELF_SERVICE_APP_URL}/work-items/${challenge.id}?tab=solutions` - } - ) - } - if (sendRejectedEmail || cancelReason) { - logger.debug('Should send redirected email') - await helper.sendSelfServiceNotification( - constants.SelfServiceNotificationTypes.WORK_REQUEST_REDIRECTED, - [{ email: creator.email }], - { - handle: creator.handle, - workItemName: challenge.name - } - ) - } - } - return challenge + return updatedChallenge; } +updateChallenge.schema = { + currentUser: Joi.any(), + challengeId: Joi.id(), + data: Joi.object() + .keys({ + legacy: Joi.object() + .keys({ + track: Joi.string(), + subTrack: Joi.string(), + reviewType: Joi.string() + .valid(_.values(constants.reviewTypes)) + .insensitive() + .default(constants.reviewTypes.Internal), + confidentialityType: Joi.string().default(config.DEFAULT_CONFIDENTIALITY_TYPE), + directProjectId: Joi.number(), + forumId: Joi.number().integer(), + isTask: Joi.boolean(), + useSchedulingAPI: Joi.boolean(), + pureV5Task: Joi.boolean(), + pureV5: Joi.boolean(), + selfService: Joi.boolean(), + selfServiceCopilot: Joi.string().allow(null), + }) + .unknown(true), + cancelReason: Joi.string().optional(), + task: Joi.object() + .keys({ + isTask: Joi.boolean().default(false), + isAssigned: Joi.boolean().default(false), + memberId: Joi.alternatives().try(Joi.string().allow(null), Joi.number().allow(null)), + }) + .optional(), + billing: Joi.object() + .keys({ + billingAccountId: Joi.string(), + markup: Joi.number().min(0).max(100), + }) + .unknown(true), + trackId: Joi.optionalId(), + typeId: Joi.optionalId(), + name: Joi.string().optional(), + description: Joi.string().optional(), + privateDescription: Joi.string().allow("").optional(), + descriptionFormat: Joi.string().optional(), + metadata: Joi.array() + .items( + Joi.object() + .keys({ + name: Joi.string().required(), + value: Joi.required(), + }) + .unknown(true) + ) + .unique((a, b) => a.name === b.name), + timelineTemplateId: Joi.string().optional(), // changing this to update migrated challenges + phases: Joi.array() + .items( + Joi.object() + .keys({ + phaseId: Joi.id(), + duration: Joi.number().integer().min(0), + isOpen: Joi.boolean(), + actualEndDate: Joi.date().allow(null), + scheduledStartDate: Joi.date().allow(null), + constraints: Joi.array() + .items( + Joi.object() + .keys({ + name: Joi.string(), + value: Joi.number().integer().min(0), + }) + .optional() + ) + .optional(), + }) + .unknown(true) + ) + .min(1) + .optional(), + events: Joi.array().items( + Joi.object() + .keys({ + id: Joi.number().required(), + name: Joi.string(), + key: Joi.string(), + }) + .unknown(true) + .optional() + ), + discussions: Joi.array() + .items( + Joi.object().keys({ + id: Joi.optionalId(), + name: Joi.string().required(), + type: Joi.string().required().valid(_.values(constants.DiscussionTypes)), + provider: Joi.string().required(), + url: Joi.string(), + options: Joi.array().items(Joi.object()), + }) + ) + .optional(), + startDate: Joi.date().iso(), + prizeSets: Joi.array() + .items( + Joi.object() + .keys({ + type: Joi.string().valid(_.values(constants.prizeSetTypes)).required(), + description: Joi.string(), + prizes: Joi.array() + .items( + Joi.object().keys({ + description: Joi.string(), + type: Joi.string().required(), + value: Joi.number().min(0).required(), + }) + ) + .min(1) + .required(), + }) + .unknown(true) + ) + .min(1), + tags: Joi.array().items(Joi.string().required()).min(1), // tag names + projectId: Joi.number().integer().positive(), + legacyId: Joi.number().integer().positive(), + status: Joi.string().valid(_.values(constants.challengeStatuses)), + attachments: Joi.array().items( + Joi.object().keys({ + id: Joi.id(), + challengeId: Joi.id(), + name: Joi.string().required(), + url: Joi.string().uri().required(), + fileSize: Joi.fileSize(), + description: Joi.string(), + }) + ), + groups: Joi.array().items(Joi.optionalId()).unique(), + // gitRepoURLs: Joi.array().items(Joi.string().uri()), + winners: Joi.array() + .items( + Joi.object() + .keys({ + userId: Joi.number().integer().positive().required(), + handle: Joi.string().required(), + placement: Joi.number().integer().positive().required(), + type: Joi.string() + .valid(_.values(constants.prizeSetTypes)) + .default(constants.prizeSetTypes.ChallengePrizes), + }) + .unknown(true) + ) + .optional(), + terms: Joi.array().items( + Joi.object().keys({ + id: Joi.id(), + roleId: Joi.id(), + }) + ), + overview: Joi.any().forbidden(), + }) + .unknown(true) + .required(), +}; + /** * Send notifications * @param {Object} currentUser the current use * @param {String} challengeId the challenge id */ -async function sendNotifications (currentUser, challengeId) { - const challenge = await getChallenge(currentUser, challengeId) - const creator = await helper.getMemberByHandle(challenge.createdBy) +async function sendNotifications(currentUser, challengeId) { + const challenge = await getChallenge(currentUser, challengeId); + const creator = await helper.getMemberByHandle(challenge.createdBy); if (challenge.status === constants.challengeStatuses.Completed) { await helper.sendSelfServiceNotification( constants.SelfServiceNotificationTypes.WORK_COMPLETED, @@ -2015,322 +2135,127 @@ async function sendNotifications (currentUser, challengeId) { { handle: creator.handle, workItemName: challenge.name, - workItemUrl: `${config.SELF_SERVICE_APP_URL}/work-items/${challenge.id}?tab=solutions` + workItemUrl: `${config.SELF_SERVICE_APP_URL}/work-items/${challenge.id}?tab=solutions`, } - ) - return { type: constants.SelfServiceNotificationTypes.WORK_COMPLETED } + ); + return { type: constants.SelfServiceNotificationTypes.WORK_COMPLETED }; } } sendNotifications.schema = { currentUser: Joi.any(), - challengeId: Joi.id() -} + challengeId: Joi.id(), +}; /** * Remove unwanted properties from the challenge object * @param {Object} challenge the challenge object */ -function sanitizeChallenge (challenge) { +function sanitizeChallenge(challenge) { const sanitized = _.pick(challenge, [ - 'trackId', - 'typeId', - 'name', - 'description', - 'privateDescription', - 'descriptionFormat', - 'timelineTemplateId', - 'tags', - 'projectId', - 'legacyId', - 'startDate', - 'status', - 'task', - 'groups', - 'cancelReason' - ]) + "trackId", + "typeId", + "name", + "description", + "privateDescription", + "descriptionFormat", + "timelineTemplateId", + "tags", + "projectId", + "legacyId", + "startDate", + "status", + "task", + "groups", + "cancelReason", + ]); if (!_.isUndefined(sanitized.name)) { - sanitized.name = xss(sanitized.name) + sanitized.name = xss(sanitized.name); } if (!_.isUndefined(sanitized.description)) { - sanitized.description = xss(sanitized.description) + sanitized.description = xss(sanitized.description); } if (challenge.legacy) { sanitized.legacy = _.pick(challenge.legacy, [ - 'track', - 'subTrack', - 'reviewType', - 'confidentialityType', - 'forumId', - 'directProjectId', - 'screeningScorecardId', - 'reviewScorecardId', - 'isTask', - 'useSchedulingAPI', - 'pureV5Task', - 'pureV5', - 'selfService', - 'selfServiceCopilot' - ]) + "track", + "subTrack", + "reviewType", + "confidentialityType", + "forumId", + "directProjectId", + "screeningScorecardId", + "reviewScorecardId", + "isTask", + "useSchedulingAPI", + "pureV5Task", + "pureV5", + "selfService", + "selfServiceCopilot", + ]); } if (challenge.billing) { - sanitized.billing = _.pick(challenge.billing, [ - 'billingAccountId', - 'markup' - ]) + sanitized.billing = _.pick(challenge.billing, ["billingAccountId", "markup"]); } if (challenge.metadata) { - sanitized.metadata = _.map(challenge.metadata, meta => _.pick(meta, ['name', 'value'])) + sanitized.metadata = _.map(challenge.metadata, (meta) => _.pick(meta, ["name", "value"])); } if (challenge.phases) { - sanitized.phases = _.map(challenge.phases, phase => _.pick(phase, ['phaseId', 'duration', 'isOpen', 'actualEndDate', 'scheduledStartDate', 'constraints'])) + sanitized.phases = _.map(challenge.phases, (phase) => + _.pick(phase, ["phaseId", "duration", "scheduledStartDate", "constraints"]) + ); } if (challenge.prizeSets) { - sanitized.prizeSets = _.map(challenge.prizeSets, prizeSet => ({ - ..._.pick(prizeSet, ['type', 'description']), - prizes: _.map(prizeSet.prizes, prize => _.pick(prize, ['description', 'type', 'value'])) - })) + sanitized.prizeSets = _.map(challenge.prizeSets, (prizeSet) => ({ + ..._.pick(prizeSet, ["type", "description"]), + prizes: _.map(prizeSet.prizes, (prize) => _.pick(prize, ["description", "type", "value"])), + })); } if (challenge.events) { - sanitized.events = _.map(challenge.events, event => _.pick(event, ['id', 'name', 'key'])) + sanitized.events = _.map(challenge.events, (event) => _.pick(event, ["id", "name", "key"])); } if (challenge.winners) { - sanitized.winners = _.map(challenge.winners, winner => _.pick(winner, ['userId', 'handle', 'placement', 'type'])) + sanitized.winners = _.map(challenge.winners, (winner) => + _.pick(winner, ["userId", "handle", "placement", "type"]) + ); } if (challenge.discussions) { - sanitized.discussions = _.map(challenge.discussions, discussion => ({ - ..._.pick(discussion, ['id', 'provider', 'name', 'type', 'url', 'options']), - name: _.get(discussion, 'name', '').substring(0, config.FORUM_TITLE_LENGTH_LIMIT) - })) + sanitized.discussions = _.map(challenge.discussions, (discussion) => ({ + ..._.pick(discussion, ["id", "provider", "name", "type", "url", "options"]), + name: _.get(discussion, "name", "").substring(0, config.FORUM_TITLE_LENGTH_LIMIT), + })); } if (challenge.terms) { - sanitized.terms = _.map(challenge.terms, term => _.pick(term, ['id', 'roleId'])) + sanitized.terms = _.map(challenge.terms, (term) => _.pick(term, ["id", "roleId"])); } if (challenge.attachments) { - sanitized.attachments = _.map(challenge.attachments, attachment => _.pick(attachment, ['id', 'name', 'url', 'fileSize', 'description', 'challengeId'])) + sanitized.attachments = _.map(challenge.attachments, (attachment) => + _.pick(attachment, ["id", "name", "url", "fileSize", "description", "challengeId"]) + ); } - return sanitized -} - -/** - * Fully update challenge. - * @param {Object} currentUser the user who perform operation - * @param {String} challengeId the challenge id - * @param {Object} data the challenge data to be updated - * @returns {Object} the updated challenge - */ -async function fullyUpdateChallenge (currentUser, challengeId, data) { - return update(currentUser, challengeId, sanitizeChallenge(data), true) -} - -fullyUpdateChallenge.schema = { - currentUser: Joi.any(), - challengeId: Joi.id(), - data: Joi.object().keys({ - legacy: Joi.object().keys({ - reviewType: Joi.string().valid(_.values(constants.reviewTypes)).insensitive().default(constants.reviewTypes.Internal), - confidentialityType: Joi.string().default(config.DEFAULT_CONFIDENTIALITY_TYPE), - forumId: Joi.number().integer(), - directProjectId: Joi.number().integer(), - screeningScorecardId: Joi.number().integer(), - reviewScorecardId: Joi.number().integer(), - isTask: Joi.boolean(), - useSchedulingAPI: Joi.boolean(), - pureV5Task: Joi.boolean(), - pureV5: Joi.boolean(), - selfService: Joi.boolean(), - selfServiceCopilot: Joi.string().allow(null) - }).unknown(true), - cancelReason: Joi.string(), - billing: Joi.object().keys({ - billingAccountId: Joi.string(), - markup: Joi.number().min(0).max(100) - }).unknown(true), - task: Joi.object().keys({ - isTask: Joi.boolean().default(false), - isAssigned: Joi.boolean().default(false), - memberId: Joi.string().allow(null) - }), - trackId: Joi.optionalId(), - typeId: Joi.optionalId(), - name: Joi.string().required(), - description: Joi.string(), - privateDescription: Joi.string(), - descriptionFormat: Joi.string(), - metadata: Joi.array().items(Joi.object().keys({ - name: Joi.string().required(), - value: Joi.required() - }).unknown(true)).unique((a, b) => a.name === b.name), - timelineTemplateId: Joi.string(), // Joi.optionalId(), - phases: Joi.array().items(Joi.object().keys({ - phaseId: Joi.id(), - duration: Joi.number().integer().min(0), - isOpen: Joi.boolean(), - actualEndDate: Joi.date().allow(null), - scheduledStartDate: Joi.date().allow(null), - constraints: Joi.array().items(Joi.object().keys({ - name: Joi.string(), - value: Joi.number().integer().min(0) - }).optional()).optional() - }).unknown(true)), - prizeSets: Joi.array().items(Joi.object().keys({ - type: Joi.string().valid(_.values(constants.prizeSetTypes)).required(), - description: Joi.string(), - prizes: Joi.array().items(Joi.object().keys({ - description: Joi.string(), - type: Joi.string().required(), - value: Joi.number().min(0).required() - })).min(1).required() - }).unknown(true)), - events: Joi.array().items(Joi.object().keys({ - id: Joi.number().required(), - name: Joi.string(), - key: Joi.string() - }).unknown(true)), - discussions: Joi.array().items(Joi.object().keys({ - id: Joi.optionalId(), - name: Joi.string().required(), - type: Joi.string().required().valid(_.values(constants.DiscussionTypes)), - provider: Joi.string().required(), - url: Joi.string(), - options: Joi.array().items(Joi.object()) - })), - tags: Joi.array().items(Joi.string()), // tag names - projectId: Joi.number().integer().positive().required(), - legacyId: Joi.number().integer().positive(), - startDate: Joi.date(), - status: Joi.string().valid(_.values(constants.challengeStatuses)).required(), - attachments: Joi.array().items(Joi.object().keys({ - id: Joi.id(), - challengeId: Joi.id(), - name: Joi.string().required(), - url: Joi.string().uri().required(), - fileSize: Joi.fileSize(), - description: Joi.string() - })), - groups: Joi.array().items(Joi.optionalId()), - // gitRepoURLs: Joi.array().items(Joi.string().uri()), - winners: Joi.array().items(Joi.object().keys({ - userId: Joi.number().integer().positive().required(), - handle: Joi.string().required(), - placement: Joi.number().integer().positive().required(), - type: Joi.string().valid(_.values(constants.prizeSetTypes)).default(constants.prizeSetTypes.ChallengePrizes) - }).unknown(true)).min(1), - terms: Joi.array().items(Joi.object().keys({ - id: Joi.id(), - roleId: Joi.id() - }).unknown(true)).optional().allow([]), - overview: Joi.any().forbidden() - }).unknown(true).required() -} -/** - * Partially update challenge. - * @param {Object} currentUser the user who perform operation - * @param {String} challengeId the challenge id - * @param {Object} data the challenge data to be updated - * @returns {Object} the updated challenge - */ -async function partiallyUpdateChallenge (currentUser, challengeId, data) { - return update(currentUser, challengeId, sanitizeChallenge(data)) + return sanitized; } -partiallyUpdateChallenge.schema = { - currentUser: Joi.any(), - challengeId: Joi.id(), - data: Joi.object().keys({ - legacy: Joi.object().keys({ - track: Joi.string(), - subTrack: Joi.string(), - reviewType: Joi.string().valid(_.values(constants.reviewTypes)).insensitive().default(constants.reviewTypes.Internal), - confidentialityType: Joi.string().default(config.DEFAULT_CONFIDENTIALITY_TYPE), - directProjectId: Joi.number(), - forumId: Joi.number().integer(), - isTask: Joi.boolean(), - useSchedulingAPI: Joi.boolean(), - pureV5Task: Joi.boolean(), - pureV5: Joi.boolean(), - selfService: Joi.boolean(), - selfServiceCopilot: Joi.string().allow(null) - }).unknown(true), - cancelReason: Joi.string(), - task: Joi.object().keys({ - isTask: Joi.boolean().default(false), - isAssigned: Joi.boolean().default(false), - memberId: Joi.string().allow(null) - }), - billing: Joi.object().keys({ - billingAccountId: Joi.string(), - markup: Joi.number().min(0).max(100) - }).unknown(true), - trackId: Joi.optionalId(), - typeId: Joi.optionalId(), - name: Joi.string(), - description: Joi.string(), - privateDescription: Joi.string(), - descriptionFormat: Joi.string(), - metadata: Joi.array().items(Joi.object().keys({ - name: Joi.string().required(), - value: Joi.required() - }).unknown(true)).unique((a, b) => a.name === b.name), - timelineTemplateId: Joi.string(), // changing this to update migrated challenges - phases: Joi.array().items(Joi.object().keys({ - phaseId: Joi.id(), - duration: Joi.number().integer().min(0), - isOpen: Joi.boolean(), - actualEndDate: Joi.date().allow(null), - scheduledStartDate: Joi.date().allow(null), - constraints: Joi.array().items(Joi.object().keys({ - name: Joi.string(), - value: Joi.number().integer().min(0) - }).optional()).optional() - }).unknown(true)).min(1), - events: Joi.array().items(Joi.object().keys({ - id: Joi.number().required(), - name: Joi.string(), - key: Joi.string() - }).unknown(true)), - discussions: Joi.array().items(Joi.object().keys({ - id: Joi.optionalId(), - name: Joi.string().required(), - type: Joi.string().required().valid(_.values(constants.DiscussionTypes)), - provider: Joi.string().required(), - url: Joi.string(), - options: Joi.array().items(Joi.object()) - })), - startDate: Joi.date(), - prizeSets: Joi.array().items(Joi.object().keys({ - type: Joi.string().valid(_.values(constants.prizeSetTypes)).required(), - description: Joi.string(), - prizes: Joi.array().items(Joi.object().keys({ - description: Joi.string(), - type: Joi.string().required(), - value: Joi.number().min(0).required() - })).min(1).required() - }).unknown(true)).min(1), - tags: Joi.array().items(Joi.string().required()).min(1), // tag names - projectId: Joi.number().integer().positive(), - legacyId: Joi.number().integer().positive(), - status: Joi.string().valid(_.values(constants.challengeStatuses)), - attachments: Joi.array().items(Joi.object().keys({ - id: Joi.id(), - challengeId: Joi.id(), - name: Joi.string().required(), - url: Joi.string().uri().required(), - fileSize: Joi.fileSize(), - description: Joi.string() - })), - groups: Joi.array().items(Joi.id()), // group names - // gitRepoURLs: Joi.array().items(Joi.string().uri()), - winners: Joi.array().items(Joi.object().keys({ - userId: Joi.number().integer().positive().required(), - handle: Joi.string().required(), - placement: Joi.number().integer().positive().required(), - type: Joi.string().valid(_.values(constants.prizeSetTypes)).default(constants.prizeSetTypes.ChallengePrizes) - }).unknown(true)).min(1), - terms: Joi.array().items(Joi.id().optional()).optional().allow([]), - overview: Joi.any().forbidden() - }).unknown(true).required() +function sanitizeData(data, challenge) { + for (const key in data) { + if (key === "phases") continue; + + if (challenge.hasOwnProperty(key)) { + if ( + (typeof data[key] === "object" || Array.isArray(data[key])) && + deepEqual(data[key], challenge[key]) + ) { + delete data[key]; + } else if ( + typeof data[key] !== "object" && + !Array.isArray(data[key]) && + data[key] === challenge[key] + ) { + delete data[key]; + } + } + } + return data; } /** @@ -2339,42 +2264,44 @@ partiallyUpdateChallenge.schema = { * @param {String} challengeId the challenge id * @returns {Object} the deleted challenge */ -async function deleteChallenge (currentUser, challengeId) { - const challenge = await helper.getById('Challenge', challengeId) +async function deleteChallenge(currentUser, challengeId) { + const challenge = await challengeDomain.lookup(getLookupCriteria("id", challengeId)); if (challenge.status !== constants.challengeStatuses.New) { - throw new errors.BadRequestError(`Challenge with status other than "${constants.challengeStatuses.New}" cannot be removed`) + throw new errors.BadRequestError( + `Challenge with status other than "${constants.challengeStatuses.New}" cannot be removed` + ); } // check groups authorization - await ensureAccessibleByGroupsAccess(currentUser, challenge) + await ensureAccessibleByGroupsAccess(currentUser, challenge); // check if user are allowed to delete the challenge - await ensureAccessibleForChallenge(currentUser, challenge) + await ensureAccessibleForChallenge(currentUser, challenge); // delete DB record - await models.Challenge.delete(challenge) + await challengeDomain.delete(getLookupCriteria("id", challengeId)); // delete ES document await esClient.delete({ - index: config.get('ES.ES_INDEX'), - type: config.get('ES.ES_TYPE'), - refresh: config.get('ES.ES_REFRESH'), - id: challengeId - }) - await helper.postBusEvent(constants.Topics.ChallengeDeleted, { id: challengeId }) - return challenge + index: config.get("ES.ES_INDEX"), + refresh: config.get("ES.ES_REFRESH"), + id: challengeId, + }); + await helper.postBusEvent(constants.Topics.ChallengeDeleted, { + id: challengeId, + }); + return challenge; } deleteChallenge.schema = { currentUser: Joi.any(), - challengeId: Joi.id() -} + challengeId: Joi.id(), +}; module.exports = { searchChallenges, createChallenge, getChallenge, - fullyUpdateChallenge, - partiallyUpdateChallenge, + updateChallenge, deleteChallenge, getChallengeStatistics, - sendNotifications -} + sendNotifications, +}; -logger.buildService(module.exports) +logger.buildService(module.exports); diff --git a/src/services/ChallengeTimelineTemplateService.js b/src/services/ChallengeTimelineTemplateService.js index a7484ef2..c0c1fd24 100644 --- a/src/services/ChallengeTimelineTemplateService.js +++ b/src/services/ChallengeTimelineTemplateService.js @@ -2,31 +2,52 @@ * This service provides operations of challenge type timeline template. */ -const _ = require('lodash') -const Joi = require('joi') -const uuid = require('uuid/v4') -const helper = require('../common/helper') -// const logger = require('../common/logger') -const errors = require('../common/errors') -const constants = require('../../app-constants') +const { GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT } = process.env; + +const _ = require("lodash"); +const { + DomainHelper: { getScanCriteria, getLookupCriteria }, +} = require("@topcoder-framework/lib-common"); + +const { ChallengeTimelineTemplateDomain } = require("@topcoder-framework/domain-challenge"); + +const Joi = require("joi"); + +const helper = require("../common/helper"); +const errors = require("../common/errors"); + +const constants = require("../../app-constants"); +const logger = require("../common/logger"); + +const challengeTrackService = require("./ChallengeTrackService"); +const challengeTypeService = require("./ChallengeTypeService"); +const timelineTemplateService = require("./TimelineTemplateService"); + +const challengeTimelineTemplateDomain = new ChallengeTimelineTemplateDomain( + GRPC_CHALLENGE_SERVER_HOST, + GRPC_CHALLENGE_SERVER_PORT +); /** * Search challenge type timeline templates. * @param {Object} criteria the search criteria - * @returns {Array} the search result + * @returns {Promise} the search result */ -async function searchChallengeTimelineTemplates (criteria) { - let records = await helper.scanAll('ChallengeTimelineTemplate') - if (criteria.typeId) records = _.filter(records, e => (criteria.typeId === e.typeId)) - if (criteria.trackId) records = _.filter(records, e => (criteria.trackId === e.trackId)) - if (criteria.timelineTemplateId) records = _.filter(records, e => (criteria.timelineTemplateId === e.timelineTemplateId)) - if (!_.isUndefined(criteria.isDefault)) records = _.filter(records, e => (e.isDefault === (_.toLower(_.toString(criteria.isDefault)) === 'true'))) +async function searchChallengeTimelineTemplates(criteria) { + const scanCriteria = getScanCriteria(_.omit(criteria, ["page", "perPage"])); + + const { items } = await challengeTimelineTemplateDomain.scan({ + criteria: scanCriteria, + }); + + const nRecords = items.length; + return { - total: records.length, + total: nRecords, page: 1, - perPage: Math.max(records.length, 10), - result: records - } + perPage: Math.max(nRecords, 10), + result: items, + }; } searchChallengeTimelineTemplates.schema = { @@ -34,22 +55,31 @@ searchChallengeTimelineTemplates.schema = { typeId: Joi.optionalId(), trackId: Joi.optionalId(), timelineTemplateId: Joi.optionalId(), - isDefault: Joi.boolean() - }) -} + isDefault: Joi.boolean(), + page: Joi.page(), + perPage: Joi.perPage(), + }), +}; /** * Unset existing default timeline template in order to create a new one * @param {String} typeId the type ID * @param {String} trackId the track ID */ -async function unsetDefaultTimelineTemplate (typeId, trackId) { - const records = await searchChallengeTimelineTemplates({ typeId, trackId, isDefault: true }) +async function unsetDefaultTimelineTemplate(typeId, trackId) { + const records = await searchChallengeTimelineTemplates({ + typeId, + trackId, + isDefault: true, + }); if (records.total === 0) { - return + return; } for (const record of records.result) { - await fullyUpdateChallengeTimelineTemplate(record.id, { ...record, isDefault: false }) + await fullyUpdateChallengeTimelineTemplate(record.id, { + ...record, + isDefault: false, + }); } } @@ -58,48 +88,53 @@ async function unsetDefaultTimelineTemplate (typeId, trackId) { * @param {Object} data the data to create challenge type timeline template * @returns {Object} the created challenge type timeline template */ -async function createChallengeTimelineTemplate (data) { +async function createChallengeTimelineTemplate(data) { // check duplicate - const records = await searchChallengeTimelineTemplates(data) + const records = await searchChallengeTimelineTemplates(data); if (records.total > 0) { - throw new errors.ConflictError('The challenge type timeline template is already defined.') + throw new errors.ConflictError("The challenge type timeline template is already defined."); } - // check exists - await helper.getById('ChallengeType', data.typeId) - await helper.getById('ChallengeTrack', data.trackId) - await helper.getById('TimelineTemplate', data.timelineTemplateId) + + await challengeTypeService.getChallengeType(data.typeId); + await challengeTrackService.getChallengeTrack(data.trackId); + await timelineTemplateService.getTimelineTemplate(data.timelineTemplateId); if (data.isDefault) { - await unsetDefaultTimelineTemplate(data.typeId, data.trackId) + await unsetDefaultTimelineTemplate(data.typeId, data.trackId); } - const ret = await helper.create('ChallengeTimelineTemplate', _.assign({ id: uuid() }, data)) + const template = await challengeTimelineTemplateDomain.create(data); + // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTimelineTemplateCreated, ret) - return ret + await helper.postBusEvent(constants.Topics.ChallengeTimelineTemplateCreated, template); + return template; } createChallengeTimelineTemplate.schema = { - data: Joi.object().keys({ - typeId: Joi.id(), - trackId: Joi.id(), - timelineTemplateId: Joi.id(), - isDefault: Joi.boolean().default(false).required() - }).required() -} + data: Joi.object() + .keys({ + typeId: Joi.id(), + trackId: Joi.id(), + timelineTemplateId: Joi.id(), + isDefault: Joi.boolean().default(false).required(), + }) + .required(), +}; /** * Get challenge type timeline template. * @param {String} challengeTimelineTemplateId the challenge type timeline template id - * @returns {Object} the challenge type timeline template with given id + * @returns {Promise} the challenge type timeline template with given id */ -async function getChallengeTimelineTemplate (challengeTimelineTemplateId) { - return helper.getById('ChallengeTimelineTemplate', challengeTimelineTemplateId) +async function getChallengeTimelineTemplate(challengeTimelineTemplateId) { + return challengeTimelineTemplateDomain.lookup( + getLookupCriteria("id", challengeTimelineTemplateId) + ); } getChallengeTimelineTemplate.schema = { - challengeTimelineTemplateId: Joi.id() -} + challengeTimelineTemplateId: Joi.id(), +}; /** * Fully update challenge type timeline template. @@ -107,64 +142,88 @@ getChallengeTimelineTemplate.schema = { * @param {Object} data the challenge type timeline template data to be updated * @returns {Object} the updated challenge type timeline template */ -async function fullyUpdateChallengeTimelineTemplate (challengeTimelineTemplateId, data) { - const record = await helper.getById('ChallengeTimelineTemplate', challengeTimelineTemplateId) - if (record.typeId === data.typeId && +async function fullyUpdateChallengeTimelineTemplate(challengeTimelineTemplateId, data) { + const record = await getChallengeTimelineTemplate(challengeTimelineTemplateId); + if ( + record.typeId === data.typeId && record.trackId === data.trackId && record.timelineTemplateId === data.timelineTemplateId && - record.isDefault === data.isDefault) { - // no change - return record + record.isDefault === data.isDefault + ) { + return record; } // check duplicate - const records = await searchChallengeTimelineTemplates(data) + const records = await searchChallengeTimelineTemplates(data); if (records.total > 0) { - throw new errors.ConflictError('The challenge type timeline template is already defined.') + throw new errors.ConflictError( + `A challenge type timeline template with typeId: ${data.typeId}, trackId: ${data.trackId}, timelineTemplateId: ${data.timelineTemplateId} already exists.` + ); } - // check exists - await helper.getById('ChallengeType', data.typeId) - await helper.getById('ChallengeTrack', data.trackId) - await helper.getById('TimelineTemplate', data.timelineTemplateId) + + await challengeTypeService.getChallengeType(data.typeId); + await challengeTrackService.getChallengeTrack(data.trackId); + await timelineTemplateService.getTimelineTemplate(data.timelineTemplateId); if (data.isDefault) { - await unsetDefaultTimelineTemplate(data.typeId, data.trackId) + await unsetDefaultTimelineTemplate(data.typeId, data.trackId); } - const ret = await helper.update(record, data) - // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTimelineTemplateUpdated, ret) - return ret + const updateInput = { + filterCriteria: getScanCriteria({ + id: challengeTimelineTemplateId, + }), + updateInput: data, + }; + + const { items } = await challengeTimelineTemplateDomain.update(updateInput); + if (items.length > 0) { + // post bus event + await helper.postBusEvent(constants.Topics.ChallengeTimelineTemplateUpdated, items[0]); + return items[0]; + } else { + throw new errors.NotFoundError( + `A challenge type timeline template with id: ${challengeTimelineTemplateId} not found.` + ); + } } fullyUpdateChallengeTimelineTemplate.schema = { challengeTimelineTemplateId: Joi.id(), - data: createChallengeTimelineTemplate.schema.data -} + data: createChallengeTimelineTemplate.schema.data, +}; /** * Delete challenge type timeline template. * @param {String} challengeTimelineTemplateId the challenge type timeline template id * @returns {Object} the deleted challenge type timeline template */ -async function deleteChallengeTimelineTemplate (challengeTimelineTemplateId) { - const ret = await helper.getById('ChallengeTimelineTemplate', challengeTimelineTemplateId) - await ret.delete() +async function deleteChallengeTimelineTemplate(challengeTimelineTemplateId) { + const { items: templates } = await challengeTimelineTemplateDomain.delete( + getLookupCriteria("id", challengeTimelineTemplateId) + ); + + if (templates.length === 0) { + throw new errors.NotFoundError( + `A challenge type timeline template with id: ${challengeTimelineTemplateId} not found.` + ); + } + // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTimelineTemplateDeleted, ret) - return ret + await helper.postBusEvent(constants.Topics.ChallengeTimelineTemplateDeleted, templates[0]); + return templates[0]; } deleteChallengeTimelineTemplate.schema = { - challengeTimelineTemplateId: Joi.id() -} + challengeTimelineTemplateId: Joi.id(), +}; module.exports = { searchChallengeTimelineTemplates, createChallengeTimelineTemplate, getChallengeTimelineTemplate, fullyUpdateChallengeTimelineTemplate, - deleteChallengeTimelineTemplate -} + deleteChallengeTimelineTemplate, +}; -// logger.buildService(module.exports) +logger.buildService(module.exports); diff --git a/src/services/ChallengeTrackService.js b/src/services/ChallengeTrackService.js index 3e9905e6..1529ec1a 100644 --- a/src/services/ChallengeTrackService.js +++ b/src/services/ChallengeTrackService.js @@ -2,40 +2,50 @@ * This service provides operations of challenge types. */ -const _ = require('lodash') -const Joi = require('joi') -const uuid = require('uuid/v4') -const helper = require('../common/helper') -// const logger = require('../common/logger') -const constants = require('../../app-constants') +const { GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT } = process.env; + +const { + DomainHelper: { getScanCriteria, getLookupCriteria }, +} = require("@topcoder-framework/lib-common"); + +const { ChallengeTrackDomain } = require("@topcoder-framework/domain-challenge"); + +const _ = require("lodash"); +const Joi = require("joi"); +const helper = require("../common/helper"); +const logger = require("../common/logger"); +const errors = require("../common/errors"); +const constants = require("../../app-constants"); + +const challengeTrackDomain = new ChallengeTrackDomain( + GRPC_CHALLENGE_SERVER_HOST, + GRPC_CHALLENGE_SERVER_PORT +); /** * Search challenge types * @param {Object} criteria the search criteria - * @returns {Object} the search result + * @returns {Promise} the search result */ -async function searchChallengeTracks (criteria) { - // TODO - move this to ES - let records = helper.getFromInternalCache('ChallengeTrack') - if (records == null) { - records = await helper.scanAll('ChallengeTrack') - helper.setToInternalCache('ChallengeTrack', records) - } +async function searchChallengeTracks(criteria) { + const scanCriteria = getScanCriteria(_.omit(criteria, ["page", "perPage"])); + const page = criteria.page || 1; + const perPage = criteria.perPage || 50; - const page = criteria.page || 1 - const perPage = criteria.perPage || 50 + const cacheKey = `ChallengeTrack${page}_${perPage}_${JSON.stringify(criteria)}`; - if (criteria.name) records = _.filter(records, e => helper.partialMatch(criteria.name, e.name)) - if (criteria.description) records = _.filter(records, e => helper.partialMatch(criteria.description, e.description)) - if (criteria.track) records = _.filter(records, e => _.toLower(criteria.track) === _.toLower(e.track)) - if (criteria.abbreviation) records = _.filter(records, e => helper.partialMatch(criteria.abbreviation, e.abbreviation)) - if (!_.isUndefined(criteria.isActive)) records = _.filter(records, e => (e.isActive === (criteria.isActive === 'true'))) - // if (criteria.legacyId) records = _.filter(records, e => (e.legacyId === criteria.legacyId)) + // TODO - move this to ES + let records = helper.getFromInternalCache(cacheKey); + if (records == null || records.length == 0) { + const { items } = await challengeTrackDomain.scan({ criteria: scanCriteria }); + records = items; + helper.setToInternalCache(cacheKey, records); + } - const total = records.length - const result = records.slice((page - 1) * perPage, page * perPage) + const total = records.length; + const result = records.slice((page - 1) * perPage, page * perPage); - return { total, page, perPage, result } + return { total, page, perPage, result }; } searchChallengeTracks.schema = { @@ -47,51 +57,61 @@ searchChallengeTracks.schema = { isActive: Joi.boolean(), abbreviation: Joi.string(), legacyId: Joi.number().integer().positive(), - track: Joi.string().valid(_.values(constants.challengeTracks)) - }) -} + track: Joi.string().valid(_.values(constants.challengeTracks)), + }), +}; /** * Create challenge type. * @param {Object} type the challenge type to created * @returns {Object} the created challenge type */ -async function createChallengeTrack (type) { - await helper.validateDuplicate('ChallengeTrack', 'name', type.name) - await helper.validateDuplicate('ChallengeTrack', 'abbreviation', type.abbreviation) - if (type.legacyId) { - await helper.validateDuplicate('ChallengeTrack', 'legacyId', type.legacyId) - } - const ret = await helper.create('ChallengeTrack', _.assign({ id: uuid() }, type)) +async function createChallengeTrack(type) { + const { items: existingByName } = await challengeTrackDomain.scan({ + criteria: getScanCriteria({ name: type.name }), + }); + if (existingByName.length > 0) + throw new errors.ConflictError(`Challenge Type with name ${type.name} already exists`); + const { items: existingByAbbr } = await challengeTrackDomain.scan({ + criteria: getScanCriteria({ abbreviation: type.abbreviation }), + }); + if (existingByAbbr.length > 0) + throw new errors.ConflictError( + `Challenge Type with abbreviation ${type.abbreviation} already exists` + ); + + const ret = await challengeTrackDomain.create(type); + helper.flushInternalCache(); // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTrackCreated, ret) - return ret + await helper.postBusEvent(constants.Topics.ChallengeTrackCreated, ret); + return ret; } createChallengeTrack.schema = { - type: Joi.object().keys({ - name: Joi.string().required(), - description: Joi.string(), - isActive: Joi.boolean().required(), - abbreviation: Joi.string().required(), - legacyId: Joi.number().integer().positive(), - track: Joi.string().valid(_.values(constants.challengeTracks)) - }).required() -} + type: Joi.object() + .keys({ + name: Joi.string().required(), + description: Joi.string(), + isActive: Joi.boolean().required(), + abbreviation: Joi.string().required(), + legacyId: Joi.number().integer().positive(), + track: Joi.string().valid(_.values(constants.challengeTracks)), + }) + .required(), +}; /** * Get challenge type. * @param {String} id the challenge type id * @returns {Object} the challenge type with given id */ -async function getChallengeTrack (id) { - const ret = await helper.getById('ChallengeTrack', id) - return ret +async function getChallengeTrack(id) { + return challengeTrackDomain.lookup(getLookupCriteria("id", id)); } getChallengeTrack.schema = { - id: Joi.id() -} + id: Joi.id(), +}; /** * Fully update challenge type. @@ -99,43 +119,56 @@ getChallengeTrack.schema = { * @param {Object} data the challenge type data to be updated * @returns {Object} the updated challenge type */ -async function fullyUpdateChallengeTrack (id, data) { - const type = await helper.getById('ChallengeTrack', id) +async function fullyUpdateChallengeTrack(id, data) { + const type = await getChallengeTrack(id); if (type.name.toLowerCase() !== data.name.toLowerCase()) { - await helper.validateDuplicate('ChallengeTrack', 'name', data.name) + const { items: existingByName } = await challengeTrackDomain.scan({ + criteria: getScanCriteria({ name: data.name }), + }); + if (existingByName.length > 0) + throw new errors.ConflictError(`Challenge Track with name ${data.name} already exists`); } if (type.abbreviation.toLowerCase() !== data.abbreviation.toLowerCase()) { - await helper.validateDuplicate('ChallengeTrack', 'abbreviation', data.abbreviation) - } - if (data.legacyId && type.legacyId !== data.legacyId) { - await helper.validateDuplicate('ChallengeTrack', 'legacyId', data.legacyId) + const { items: existingByAbbr } = await challengeTrackDomain.scan({ + criteria: getScanCriteria({ abbreviation: data.abbreviation }), + }); + if (existingByAbbr.length > 0) + throw new errors.ConflictError( + `Challenge Type with abbreviation ${data.abbreviation} already exists` + ); } if (_.isUndefined(data.description)) { - type.description = undefined + type.description = undefined; } if (_.isUndefined(data.legacyId)) { - type.legacyId = undefined + type.legacyId = undefined; } if (_.isUndefined(data.track)) { - type.track = undefined + type.track = undefined; } - const ret = await helper.update(type, data) + const { items } = await challengeTrackDomain.update({ + filterCriteria: getScanCriteria({ id }), + updateInput: _.extend(type, data), + }); + helper.flushInternalCache(); // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTrackUpdated, ret) - return ret + await helper.postBusEvent(constants.Topics.ChallengeTrackUpdated, items[0]); + return items[0]; } fullyUpdateChallengeTrack.schema = { id: Joi.id(), - data: Joi.object().keys({ - name: Joi.string().required(), - description: Joi.string(), - isActive: Joi.boolean().required(), - abbreviation: Joi.string().required(), - legacyId: Joi.number().integer().positive(), - track: Joi.string().valid(_.values(constants.challengeTracks)) - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string().required(), + description: Joi.string(), + isActive: Joi.boolean().required(), + abbreviation: Joi.string().required(), + legacyId: Joi.number().integer().positive(), + track: Joi.string().valid(_.values(constants.challengeTracks)), + }) + .required(), +}; /** * Partially update challenge type. @@ -143,51 +176,66 @@ fullyUpdateChallengeTrack.schema = { * @param {Object} data the challenge type data to be updated * @returns {Object} the updated challenge type */ -async function partiallyUpdateChallengeTrack (id, data) { - const type = await helper.getById('ChallengeTrack', id) +async function partiallyUpdateChallengeTrack(id, data) { + const type = await getChallengeTrack(id); if (data.name && type.name.toLowerCase() !== data.name.toLowerCase()) { - await helper.validateDuplicate('ChallengeTrack', 'name', data.name) + const { items: existingByName } = await challengeTrackDomain.scan({ + criteria: getScanCriteria({ name: data.name }), + }); + if (existingByName.length > 0) + throw new errors.ConflictError(`Challenge Track with name ${data.name} already exists`); } if (data.abbreviation && type.abbreviation.toLowerCase() !== data.abbreviation.toLowerCase()) { - await helper.validateDuplicate('ChallengeTrack', 'abbreviation', data.abbreviation) - } - if (data.legacyId && type.legacyId !== data.legacyId) { - await helper.validateDuplicate('ChallengeTrack', 'legacyId', data.legacyId) + const { items: existingByAbbr } = await challengeTrackDomain.scan({ + criteria: getScanCriteria({ abbreviation: data.abbreviation }), + }); + if (existingByAbbr.length > 0) + throw new errors.ConflictError( + `Challenge Type with abbreviation ${data.abbreviation} already exists` + ); } - const ret = await helper.update(type, data) + + const { items } = await challengeTrackDomain.update({ + filterCriteria: getScanCriteria({ id }), + updateInput: _.extend(type, data), + }); + helper.flushInternalCache(); // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTrackUpdated, _.assignIn({ id }, data)) - return ret + await helper.postBusEvent(constants.Topics.ChallengeTrackUpdated, _.assignIn({ id }, data)); + return items[0]; } partiallyUpdateChallengeTrack.schema = { id: Joi.id(), - data: Joi.object().keys({ - name: Joi.string(), - description: Joi.string(), - isActive: Joi.boolean(), - abbreviation: Joi.string(), - legacyId: Joi.number().integer().positive(), - track: Joi.string().valid(_.values(constants.challengeTracks)) - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string(), + description: Joi.string(), + isActive: Joi.boolean(), + abbreviation: Joi.string(), + legacyId: Joi.number().integer().positive(), + track: Joi.string().valid(_.values(constants.challengeTracks)), + }) + .required(), +}; /** * Delete challenge track. * @param {String} id the challenge track id * @return {Object} the deleted challenge track */ -async function deleteChallengeTrack (id) { - const record = await helper.getById('ChallengeTrack', id) - await record.delete() +async function deleteChallengeTrack(id) { + const { items } = await challengeTrackDomain.delete(getLookupCriteria("id", id)); + helper.flushInternalCache(); + // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTrackDeleted, record) - return record + await helper.postBusEvent(constants.Topics.ChallengeTypeDeleted, items[0]); + return items[0]; } deleteChallengeTrack.schema = { - id: Joi.id() -} + id: Joi.id(), +}; module.exports = { searchChallengeTracks, @@ -195,7 +243,7 @@ module.exports = { getChallengeTrack, fullyUpdateChallengeTrack, partiallyUpdateChallengeTrack, - deleteChallengeTrack -} + deleteChallengeTrack, +}; -// logger.buildService(module.exports) +logger.buildService(module.exports); diff --git a/src/services/ChallengeTypeService.js b/src/services/ChallengeTypeService.js index 71072694..4a1afc60 100644 --- a/src/services/ChallengeTypeService.js +++ b/src/services/ChallengeTypeService.js @@ -2,37 +2,50 @@ * This service provides operations of challenge tracks. */ -const _ = require('lodash') -const Joi = require('joi') -const uuid = require('uuid/v4') -const helper = require('../common/helper') -const constants = require('../../app-constants') +const { GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT } = process.env; + +const { + DomainHelper: { getLookupCriteria, getScanCriteria }, +} = require("@topcoder-framework/lib-common"); + +const { ChallengeTypeDomain } = require("@topcoder-framework/domain-challenge"); + +const _ = require("lodash"); +const Joi = require("joi"); +const helper = require("../common/helper"); +const constants = require("../../app-constants"); +const errors = require("../common/errors"); + +const challengeTypeDomain = new ChallengeTypeDomain( + GRPC_CHALLENGE_SERVER_HOST, + GRPC_CHALLENGE_SERVER_PORT +); /** * Search challenge types * @param {Object} criteria the search criteria * @returns {Object} the search result */ -async function searchChallengeTypes (criteria) { +async function searchChallengeTypes(criteria) { + const scanCriteria = getScanCriteria(_.omit(criteria, ["page", "perPage"])); + + const page = criteria.page || 1; + const perPage = criteria.perPage || 50; + + const cacheKey = `ChallengeType_${page}_${perPage}_${JSON.stringify(criteria)}`; + // TODO - move this to ES - let records = helper.getFromInternalCache('ChallengeType') - if (records == null) { - records = await helper.scanAll('ChallengeType') - helper.setToInternalCache('ChallengeType', records) + let records = helper.getFromInternalCache(cacheKey); + if (records == null || records.length === 0) { + const { items } = await challengeTypeDomain.scan({ criteria: scanCriteria }); + records = items; + helper.setToInternalCache(cacheKey, records); } - const page = criteria.page || 1 - const perPage = criteria.perPage || 50 - if (criteria.name) records = _.filter(records, e => helper.partialMatch(criteria.name, e.name)) - if (criteria.description) records = _.filter(records, e => helper.partialMatch(criteria.description, e.description)) - if (criteria.abbreviation) records = _.filter(records, e => helper.partialMatch(criteria.abbreviation, e.abbreviation)) - if (!_.isUndefined(criteria.isActive)) records = _.filter(records, e => (e.isActive === (criteria.isActive === 'true'))) - if (!_.isUndefined(criteria.isTask)) records = _.filter(records, e => (e.isTask === (criteria.isTask === 'true'))) + const total = records.length; + const result = records.slice((page - 1) * perPage, page * perPage); - const total = records.length - const result = records.slice((page - 1) * perPage, page * perPage) - - return { total, page, perPage, result } + return { total, page, perPage, result }; } searchChallengeTypes.schema = { @@ -43,47 +56,59 @@ searchChallengeTypes.schema = { description: Joi.string(), isActive: Joi.boolean(), isTask: Joi.boolean().default(false), - abbreviation: Joi.string() - }) -} + abbreviation: Joi.string(), + }), +}; /** * Create challenge type. * @param {Object} type the challenge type to created * @returns {Object} the created challenge type */ -async function createChallengeType (type) { - await helper.validateDuplicate('ChallengeType', 'name', type.name) - await helper.validateDuplicate('ChallengeType', 'abbreviation', type.abbreviation) - const ret = await helper.create('ChallengeType', _.assign({ id: uuid() }, type)) +async function createChallengeType(type) { + const { items: existingByName } = await challengeTypeDomain.scan({ + criteria: getScanCriteria({ name: type.name }), + }); + if (existingByName.length > 0) + throw new errors.ConflictError(`Challenge Type with name ${type.name} already exists`); + const { items: existingByAbbr } = await challengeTypeDomain.scan({ + criteria: getScanCriteria({ abbreviation: type.abbreviation }), + }); + if (existingByAbbr.length > 0) + throw new errors.ConflictError( + `Challenge Type with abbreviation ${type.abbreviation} already exists` + ); + const ret = await challengeTypeDomain.create(type); + helper.flushInternalCache(); // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTypeCreated, ret) - return ret + await helper.postBusEvent(constants.Topics.ChallengeTypeCreated, ret); + return ret; } createChallengeType.schema = { - type: Joi.object().keys({ - name: Joi.string().required(), - description: Joi.string(), - isActive: Joi.boolean().required(), - isTask: Joi.boolean().default(false), - abbreviation: Joi.string().required() - }).required() -} + type: Joi.object() + .keys({ + name: Joi.string().required(), + description: Joi.string(), + isActive: Joi.boolean().required(), + isTask: Joi.boolean().default(false), + abbreviation: Joi.string().required(), + }) + .required(), +}; /** * Get challenge type. * @param {String} id the challenge type id * @returns {Object} the challenge type with given id */ -async function getChallengeType (id) { - const ret = await helper.getById('ChallengeType', id) - return ret +async function getChallengeType(id) { + return await challengeTypeDomain.lookup(getLookupCriteria("id", id)); } getChallengeType.schema = { - id: Joi.id() -} + id: Joi.id(), +}; /** * Fully update challenge type. @@ -91,33 +116,48 @@ getChallengeType.schema = { * @param {Object} data the challenge type data to be updated * @returns {Object} the updated challenge type */ -async function fullyUpdateChallengeType (id, data) { - const type = await helper.getById('ChallengeType', id) +async function fullyUpdateChallengeType(id, data) { + const type = await getChallengeType(id); if (type.name.toLowerCase() !== data.name.toLowerCase()) { - await helper.validateDuplicate('ChallengeType', 'name', data.name) + const { items: existingByName } = await challengeTypeDomain.scan({ + criteria: getScanCriteria({ name: data.name }), + }); + if (existingByName.length > 0) + throw new errors.ConflictError(`Challenge Type with name ${data.name} already exists`); } if (type.abbreviation.toLowerCase() !== data.abbreviation.toLowerCase()) { - await helper.validateDuplicate('ChallengeType', 'abbreviation', data.abbreviation) + const { items: existingByAbbr } = await challengeTypeDomain.scan({ + criteria: getScanCriteria({ abbreviation: data.abbreviation }), + }); + if (existingByAbbr.length > 0) + throw new errors.ConflictError( + `Challenge Type with abbreviation ${data.abbreviation} already exists` + ); } if (_.isUndefined(data.description)) { - type.description = undefined + type.description = undefined; } - const ret = await helper.update(type, data) + const { items } = await challengeTypeDomain.update({ + filterCriteria: getScanCriteria({ id }), + updateInput: data, + }); + helper.flushInternalCache(); // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTypeUpdated, ret) - return ret + await helper.postBusEvent(constants.Topics.ChallengeTypeUpdated, items[0]); + return items[0]; } - fullyUpdateChallengeType.schema = { id: Joi.id(), - data: Joi.object().keys({ - name: Joi.string().required(), - description: Joi.string(), - isActive: Joi.boolean().required(), - isTask: Joi.boolean().default(false), - abbreviation: Joi.string().required() - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string().required(), + description: Joi.string(), + isActive: Joi.boolean().required(), + isTask: Joi.boolean().default(false), + abbreviation: Joi.string().required(), + }) + .required(), +}; /** * Partially update challenge type. @@ -125,47 +165,63 @@ fullyUpdateChallengeType.schema = { * @param {Object} data the challenge type data to be updated * @returns {Object} the updated challenge type */ -async function partiallyUpdateChallengeType (id, data) { - const type = await helper.getById('ChallengeType', id) +async function partiallyUpdateChallengeType(id, data) { + const type = await getChallengeType(id); if (data.name && type.name.toLowerCase() !== data.name.toLowerCase()) { - await helper.validateDuplicate('ChallengeType', 'name', data.name) + const { items: existingByName } = await challengeTypeDomain.scan({ + criteria: getScanCriteria({ name: data.name }), + }); + if (existingByName.length > 0) + throw new errors.ConflictError(`Challenge Type with name ${data.name} already exists`); } if (data.abbreviation && type.abbreviation.toLowerCase() !== data.abbreviation.toLowerCase()) { - await helper.validateDuplicate('ChallengeType', 'abbreviation', data.abbreviation) + const { items: existingByAbbr } = await challengeTypeDomain.scan({ + criteria: getScanCriteria({ abbreviation: data.abbreviation }), + }); + if (existingByAbbr.length > 0) + throw new errors.ConflictError( + `Challenge Type with abbreviation ${data.abbreviation} already exists` + ); } - const ret = await helper.update(type, data) + const { items } = await challengeTypeDomain.update({ + filterCriteria: getScanCriteria({ id }), + updateInput: _.extend(type, data), + }); + helper.flushInternalCache(); // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTypeUpdated, _.assignIn({ id }, data)) - return ret + await helper.postBusEvent(constants.Topics.ChallengeTypeUpdated, _.assignIn({ id }, data)); + return items[0]; } partiallyUpdateChallengeType.schema = { id: Joi.id(), - data: Joi.object().keys({ - name: Joi.string(), - description: Joi.string(), - isActive: Joi.boolean(), - isTask: Joi.boolean().default(false), - abbreviation: Joi.string() - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string(), + description: Joi.string(), + isActive: Joi.boolean(), + isTask: Joi.boolean().default(false), + abbreviation: Joi.string(), + }) + .required(), +}; /** * Delete challenge type. * @param {String} id the challenge type id * @returns {Object} the deleted challenge type */ -async function deleteChallengeType (id) { - const ret = await helper.getById('ChallengeType', id) - await ret.delete() +async function deleteChallengeType(id) { + const { items } = await challengeTypeDomain.delete(getLookupCriteria("id", id)); + helper.flushInternalCache(); // post bus event - await helper.postBusEvent(constants.Topics.ChallengeTypeDeleted, ret) - return ret + await helper.postBusEvent(constants.Topics.ChallengeTypeDeleted, items[0]); + return items[0]; } deleteChallengeType.schema = { - id: Joi.id() -} + id: Joi.id(), +}; module.exports = { searchChallengeTypes, @@ -173,7 +229,11 @@ module.exports = { getChallengeType, fullyUpdateChallengeType, partiallyUpdateChallengeType, - deleteChallengeType -} - -// logger.buildService(module.exports) + deleteChallengeType, +}; + +// logger.buildService(module.exports, { +// tracing: { +// enabled: true +// } +// }) diff --git a/src/services/PhaseService.js b/src/services/PhaseService.js index f39bb70d..45b378fe 100644 --- a/src/services/PhaseService.js +++ b/src/services/PhaseService.js @@ -1,72 +1,92 @@ /** * This service provides operations of phases. */ +const { GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT } = process.env; -const _ = require('lodash') -const Joi = require('joi') -const uuid = require('uuid/v4') -const helper = require('../common/helper') -// const logger = require('../common/logger') -const constants = require('../../app-constants') +const { PhaseDomain } = require("@topcoder-framework/domain-challenge"); + +const { + DomainHelper: { getScanCriteria, getLookupCriteria }, +} = require("@topcoder-framework/lib-common"); + +const _ = require("lodash"); +const Joi = require("joi"); +const helper = require("../common/helper"); +const logger = require("../common/logger"); +const constants = require("../../app-constants"); +const errors = require("../common/errors"); + +const phaseDomain = new PhaseDomain(GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT); /** * Search phases * @param {Object} criteria the search criteria * @returns {Object} the search result */ -async function searchPhases (criteria) { - const page = criteria.page || 1 - const perPage = criteria.perPage || 50 - const list = await helper.scanAll('Phase') - const records = _.filter(list, e => helper.partialMatch(criteria.name, e.name)) - const total = records.length - const result = records.slice((page - 1) * perPage, page * perPage) - - return { total, page, perPage, result } +async function searchPhases(criteria = {}) { + const scanCriteria = getScanCriteria(_.omit(criteria, ["page", "perPage"])); + + const page = criteria.page || 1; + const perPage = criteria.perPage || 50; + + const { items: list } = await phaseDomain.scan({ + criteria: scanCriteria, + }); + + const total = list.length; + const result = list.slice((page - 1) * perPage, page * perPage); + + return { total, page, perPage, result }; } searchPhases.schema = { criteria: Joi.object().keys({ page: Joi.page(), perPage: Joi.perPage().default(100), - name: Joi.string() - }) -} + name: Joi.string(), + }), +}; /** * Create phase. * @param {Object} phase the phase to created * @returns {Object} the created phase */ -async function createPhase (phase) { - await helper.validateDuplicate('Phase', 'name', phase.name) - const ret = await helper.create('Phase', _.assign({ id: uuid() }, phase)) +async function createPhase(phase) { + const { items: existingByName } = await phaseDomain.scan({ + criteria: getScanCriteria({ name: phase.name }), + }); + if (existingByName.length > 0) + throw new errors.ConflictError(`Phase with name ${phase.name} already exists`); + const ret = await phaseDomain.create(phase); // post bus event - await helper.postBusEvent(constants.Topics.ChallengePhaseCreated, ret) - return ret + await helper.postBusEvent(constants.Topics.ChallengePhaseCreated, ret); + return ret; } createPhase.schema = { - phase: Joi.object().keys({ - name: Joi.string().required(), - description: Joi.string(), - isOpen: Joi.boolean().required(), - duration: Joi.number().positive().required() - }).required() -} + phase: Joi.object() + .keys({ + name: Joi.string().required(), + description: Joi.string(), + isOpen: Joi.boolean().required(), + duration: Joi.number().positive().required(), + }) + .required(), +}; /** * Get phase * @param {String} phaseId the phase id * @returns {Object} the phase with given id */ -async function getPhase (phaseId) { - return helper.getById('Phase', phaseId) +async function getPhase(phaseId) { + return phaseDomain.lookup(getLookupCriteria("id", phaseId)); } getPhase.schema = { - phaseId: Joi.id() -} + phaseId: Joi.id(), +}; /** * Update phase. @@ -75,23 +95,32 @@ getPhase.schema = { * @param {Boolean} isFull the flag indicate it is a fully update operation. * @returns {Object} the updated phase */ -async function update (phaseId, data, isFull) { - const phase = await helper.getById('Phase', phaseId) +async function update(phaseId, data, isFull) { + const phase = await getPhase(phaseId); if (data.name && data.name.toLowerCase() !== phase.name.toLowerCase()) { - await helper.validateDuplicate('Phase', 'name', data.name) + const { items } = await phaseDomain.scan({ + criteria: getScanCriteria({ name: data.name }), + }); + console.log("items", items); + if (items.length > 0) + throw new errors.ConflictError(`Phase with name ${phase.name} already exists`); } if (isFull) { // description is optional field, can be undefined - phase.description = data.description + phase.description = data.description; } - - const ret = await helper.update(phase, data) + const { items } = await phaseDomain.update({ + filterCriteria: getScanCriteria({ id: phaseId }), + updateInput: data, + }); // post bus event - await helper.postBusEvent(constants.Topics.ChallengePhaseUpdated, - isFull ? ret : _.assignIn({ id: phaseId }, data)) - return ret + await helper.postBusEvent( + constants.Topics.ChallengePhaseUpdated, + isFull ? items[0] : _.assignIn({ id: phaseId }, data) + ); + return items[0]; } /** @@ -100,19 +129,21 @@ async function update (phaseId, data, isFull) { * @param {Object} data the phase data to be updated * @returns {Object} the updated phase */ -async function fullyUpdatePhase (phaseId, data) { - return update(phaseId, data, true) +async function fullyUpdatePhase(phaseId, data) { + return update(phaseId, data, true); } fullyUpdatePhase.schema = { phaseId: Joi.id(), - data: Joi.object().keys({ - name: Joi.string().required(), - description: Joi.string(), - isOpen: Joi.boolean().required(), - duration: Joi.number().positive().required() - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string().required(), + description: Joi.string(), + isOpen: Joi.boolean().required(), + duration: Joi.number().positive().required(), + }) + .required(), +}; /** * Partially update phase. @@ -120,44 +151,64 @@ fullyUpdatePhase.schema = { * @param {Object} data the phase data to be updated * @returns {Object} the updated phase */ -async function partiallyUpdatePhase (phaseId, data) { - return update(phaseId, data) +async function partiallyUpdatePhase(phaseId, data) { + return update(phaseId, data); } partiallyUpdatePhase.schema = { phaseId: Joi.id(), - data: Joi.object().keys({ - name: Joi.string(), - description: Joi.string(), - isOpen: Joi.boolean(), - duration: Joi.number().positive() - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string(), + description: Joi.string(), + isOpen: Joi.boolean(), + duration: Joi.number().positive(), + }) + .required(), +}; /** * Delete phase. * @param {String} phaseId the phase id * @returns {Object} the deleted phase */ -async function deletePhase (phaseId) { - const ret = await helper.getById('Phase', phaseId) - await ret.delete() +async function deletePhase(phaseId) { + const { items } = await phaseDomain.delete(getLookupCriteria("id", phaseId)); // post bus event - await helper.postBusEvent(constants.Topics.ChallengePhaseDeleted, ret) - return ret + await helper.postBusEvent(constants.Topics.ChallengePhaseDeleted, items[0]); + return items[0]; } deletePhase.schema = { - phaseId: Joi.id() + phaseId: Joi.id(), +}; + +async function validatePhases(phases) { + if (!phases || phases.length === 0) { + return; + } + const searchPhasesResult = await searchPhases(); // get all phases + const records = searchPhasesResult.result; + const map = new Map(); + _.each(records, (r) => { + map.set(r.id, r); + }); + const invalidPhases = _.filter(phases, (p) => !map.has(p.phaseId)); + if (invalidPhases.length > 0) { + throw new errors.BadRequestError( + `The following phases are invalid: ${toString(invalidPhases)}` + ); + } } module.exports = { searchPhases, createPhase, + validatePhases, getPhase, fullyUpdatePhase, partiallyUpdatePhase, - deletePhase -} + deletePhase, +}; -// logger.buildService(module.exports) +logger.buildService(module.exports); diff --git a/src/services/SupportService.js b/src/services/SupportService.js index c245cee8..bdf6a62f 100644 --- a/src/services/SupportService.js +++ b/src/services/SupportService.js @@ -2,11 +2,11 @@ * This service provides operations of support requests. */ -const _ = require('lodash') -const Joi = require('joi') -const config = require('config') -const helper = require('../common/helper') -const logger = require('../common/logger') +const _ = require("lodash"); +const Joi = require("joi"); +const config = require("config"); +const helper = require("../common/helper"); +const logger = require("../common/logger"); /** * Create a request in zendesk @@ -14,35 +14,37 @@ const logger = require('../common/logger') * @param {Object} request the request * @returns {Object} the search result */ -async function createRequest (currentUser, request) { - let subject +async function createRequest(currentUser, request) { + let subject; if (request.isSelfService) { - subject += 'Self-Service customer support request' + subject += "Self-Service customer support request"; } else { - subject = 'General support request' + subject = "General support request"; } if (request.challengeId) { - subject += ` for Challenge ID: ${request.challengeId}` + subject += ` for Challenge ID: ${request.challengeId}`; } - return await helper.submitZendeskRequest({ + return helper.submitZendeskRequest({ requester: { name: `${request.firstName} ${request.lastName}`, - email: request.email + email: request.email, }, subject, comment: { - body: request.question + body: request.question, }, priority: config.ZENDESK_DEFAULT_PRIORITY, - ...(request.isSelfService && config.ZENDESK_CUSTOM_FIELD_TAG_ID ? { - custom_fields: [ - { - id: _.toNumber(config.ZENDESK_CUSTOM_FIELD_TAG_ID), - value: 'self_service' + ...(request.isSelfService && config.ZENDESK_CUSTOM_FIELD_TAG_ID + ? { + custom_fields: [ + { + id: _.toNumber(config.ZENDESK_CUSTOM_FIELD_TAG_ID), + value: "self_service", + }, + ], } - ] - } : {}) - }) + : {}), + }); } createRequest.schema = { @@ -53,12 +55,12 @@ createRequest.schema = { firstName: Joi.string().required(), lastName: Joi.string().required(), isSelfService: Joi.boolean(), - question: Joi.string().required() - }) -} + question: Joi.string().required(), + }), +}; module.exports = { - createRequest -} + createRequest, +}; -logger.buildService(module.exports) +logger.buildService(module.exports); diff --git a/src/services/TimelineTemplateService.js b/src/services/TimelineTemplateService.js index 65479518..ecb56894 100644 --- a/src/services/TimelineTemplateService.js +++ b/src/services/TimelineTemplateService.js @@ -2,78 +2,120 @@ * This service provides operations of timeline template. */ -const _ = require('lodash') -const Joi = require('joi') -const uuid = require('uuid/v4') -const helper = require('../common/helper') -const phaseHelper = require('../common/phase-helper') -// const logger = require('../common/logger') -const constants = require('../../app-constants') +const { GRPC_CHALLENGE_SERVER_HOST, GRPC_CHALLENGE_SERVER_PORT } = process.env; + +const { + DomainHelper: { getScanCriteria, getLookupCriteria }, +} = require("@topcoder-framework/lib-common"); + +const { TimelineTemplateDomain } = require("@topcoder-framework/domain-challenge"); + +const _ = require("lodash"); +const Joi = require("joi"); +const helper = require("../common/helper"); +const logger = require("../common/logger"); +const constants = require("../../app-constants"); +const errors = require("../common/errors"); + +const PhaseService = require("./PhaseService"); + +const timelineTemplateDomain = new TimelineTemplateDomain( + GRPC_CHALLENGE_SERVER_HOST, + GRPC_CHALLENGE_SERVER_PORT +); + +module.exports = {}; /** * Search timeline templates. * @param {Object} criteria the search criteria - * @returns {Object} the search result + * @returns {Promise} the search result */ -async function searchTimelineTemplates (criteria) { - const page = criteria.page || 1 - const perPage = criteria.perPage || 50 - const list = await helper.scanAll('TimelineTemplate') - const records = _.filter(list, e => helper.partialMatch(criteria.name, e.name)) - const total = records.length - const result = records.slice((page - 1) * perPage, page * perPage) - - return { total, page, perPage, result } +async function searchTimelineTemplates(criteria) { + const scanCriteria = getScanCriteria(_.omit(criteria, ["page", "perPage"])); + + const page = criteria.page || 1; + const perPage = criteria.perPage || 50; + const { items } = await timelineTemplateDomain.scan({ + criteria: scanCriteria, + }); + + const total = items.length; + const result = items.slice((page - 1) * perPage, page * perPage); + + return { total, page, perPage, result }; } searchTimelineTemplates.schema = { criteria: Joi.object().keys({ page: Joi.page(), perPage: Joi.perPage(), - name: Joi.string() - }) -} + name: Joi.string(), + }), +}; /** * Create timeline template. * @param {Object} timelineTemplate the timeline template to created * @returns {Object} the created timeline template */ -async function createTimelineTemplate (timelineTemplate) { - await helper.validateDuplicate('TimelineTemplate', 'name', timelineTemplate.name) - await phaseHelper.validatePhases(timelineTemplate.phases) +async function createTimelineTemplate(timelineTemplate) { + // await helper.validateDuplicate('TimelineTemplate', 'name', timelineTemplate.name) + // await phaseHelper.validatePhases(timelineTemplate.phases) + + const scanCriteria = getScanCriteria({ + name: timelineTemplate.name, + }); + + const existing = await timelineTemplateDomain.scan({ criteria: scanCriteria }); - const ret = await helper.create('TimelineTemplate', _.assign({ id: uuid() }, timelineTemplate)) + if (existing && existing.items.length) { + throw new errors.ConflictError( + `Timeline template with name ${timelineTemplate.name} already exists` + ); + } + + // Do not validate phases for now + // await phaseHelper.validatePhases(timelineTemplate.phases); + + const ret = await timelineTemplateDomain.create(timelineTemplate); // post bus event - await helper.postBusEvent(constants.Topics.TimelineTemplateCreated, ret) - return ret + await helper.postBusEvent(constants.Topics.TimelineTemplateCreated, ret); + return ret; } createTimelineTemplate.schema = { - timelineTemplate: Joi.object().keys({ - name: Joi.string().required(), - description: Joi.string(), - isActive: Joi.boolean().required(), - phases: Joi.array().items(Joi.object().keys({ - phaseId: Joi.id(), - predecessor: Joi.optionalId(), - defaultDuration: Joi.number().positive().required() - })).min(1).required() - }).required() -} + timelineTemplate: Joi.object() + .keys({ + name: Joi.string().required(), + description: Joi.string(), + isActive: Joi.boolean().required(), + phases: Joi.array() + .items( + Joi.object().keys({ + phaseId: Joi.id(), + predecessor: Joi.optionalId(), + defaultDuration: Joi.number().positive().required(), + }) + ) + .min(1) + .required(), + }) + .required(), +}; /** * Get timeline template. * @param {String} timelineTemplateId the timeline template id * @returns {Object} the timeline template with given id */ -async function getTimelineTemplate (timelineTemplateId) { - return helper.getById('TimelineTemplate', timelineTemplateId) +async function getTimelineTemplate(timelineTemplateId) { + return timelineTemplateDomain.lookup(getLookupCriteria("id", timelineTemplateId)); } getTimelineTemplate.schema = { - timelineTemplateId: Joi.id() -} + timelineTemplateId: Joi.id(), +}; /** * Update timeline template. @@ -82,27 +124,42 @@ getTimelineTemplate.schema = { * @param {Boolean} isFull the flag indicate it is a fully update operation. * @returns {Object} the updated timeline template */ -async function update (timelineTemplateId, data, isFull) { - const timelineTemplate = await helper.getById('TimelineTemplate', timelineTemplateId) +async function update(timelineTemplateId, data, isFull) { + const timelineTemplate = await getTimelineTemplate(timelineTemplateId); if (data.name && data.name.toLowerCase() !== timelineTemplate.name.toLowerCase()) { - await helper.validateDuplicate('TimelineTemplate', 'name', data.name) + const { items: existingByName } = await timelineTemplateDomain.scan({ + criteria: getScanCriteria({ name: data.name }), + }); + + if (existingByName.length > 1) + throw new errors.ConflictError(`Timeline template with name ${data.name} already exists`); + else if (existingByName.length === 1 && existingByName[0].id !== timelineTemplateId) + throw new errors.ConflictError(`Timeline template with name ${data.name} already exists`); } if (data.phases) { - await phaseHelper.validatePhases(data.phases) + await PhaseService.validatePhases(data.phases); } if (isFull) { // description is optional field, can be undefined - timelineTemplate.description = data.description + timelineTemplate.description = data.description; + } else { + data = { ...timelineTemplate, ...data }; } - const ret = await helper.update(timelineTemplate, data) + const { items } = await timelineTemplateDomain.update({ + filterCriteria: getScanCriteria({ id: timelineTemplateId }), + updateInput: data, + }); + // post bus event - await helper.postBusEvent(constants.Topics.TimelineTemplateUpdated, - isFull ? ret : _.assignIn({ id: timelineTemplateId }, data)) - return ret + await helper.postBusEvent( + constants.Topics.TimelineTemplateUpdated, + isFull ? items[0] : _.assignIn({ id: timelineTemplateId }, data) + ); + return items[0]; } /** @@ -111,23 +168,30 @@ async function update (timelineTemplateId, data, isFull) { * @param {Object} data the timeline template data to be updated * @returns {Object} the updated timeline template */ -async function fullyUpdateTimelineTemplate (timelineTemplateId, data) { - return update(timelineTemplateId, data, true) +async function fullyUpdateTimelineTemplate(timelineTemplateId, data) { + return update(timelineTemplateId, data, true); } fullyUpdateTimelineTemplate.schema = { timelineTemplateId: Joi.id(), - data: Joi.object().keys({ - name: Joi.string().required(), - description: Joi.string(), - isActive: Joi.boolean().required(), - phases: Joi.array().items(Joi.object().keys({ - phaseId: Joi.id(), - predecessor: Joi.optionalId(), - defaultDuration: Joi.number().positive().required() - })).min(1).required() - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string().required(), + description: Joi.string(), + isActive: Joi.boolean().required(), + phases: Joi.array() + .items( + Joi.object().keys({ + phaseId: Joi.id(), + predecessor: Joi.optionalId(), + defaultDuration: Joi.number().positive().required(), + }) + ) + .min(1) + .required(), + }) + .required(), +}; /** * Partially update timeline template. @@ -135,48 +199,53 @@ fullyUpdateTimelineTemplate.schema = { * @param {Object} data the timeline template data to be updated * @returns {Object} the updated timeline template */ -async function partiallyUpdateTimelineTemplate (timelineTemplateId, data) { - return update(timelineTemplateId, data) +async function partiallyUpdateTimelineTemplate(timelineTemplateId, data) { + return update(timelineTemplateId, data); } partiallyUpdateTimelineTemplate.schema = { timelineTemplateId: Joi.id(), - data: Joi.object().keys({ - name: Joi.string(), - description: Joi.string(), - isActive: Joi.boolean(), - phases: Joi.array().items(Joi.object().keys({ - phaseId: Joi.id(), - predecessor: Joi.optionalId(), - defaultDuration: Joi.number().positive().required() - })).min(1) - }).required() -} + data: Joi.object() + .keys({ + name: Joi.string(), + description: Joi.string(), + isActive: Joi.boolean(), + phases: Joi.array() + .items( + Joi.object().keys({ + phaseId: Joi.id(), + predecessor: Joi.optionalId(), + defaultDuration: Joi.number().positive().required(), + }) + ) + .min(1), + }) + .required(), +}; /** * Delete timeline template. * @param {String} timelineTemplateId the timeline template id * @returns {Object} the deleted timeline template */ -async function deleteTimelineTemplate (timelineTemplateId) { - const ret = await helper.getById('TimelineTemplate', timelineTemplateId) - await ret.delete() +async function deleteTimelineTemplate(timelineTemplateId) { + const { items } = await timelineTemplateDomain.delete( + getLookupCriteria("id", timelineTemplateId) + ); // post bus event - await helper.postBusEvent(constants.Topics.TimelineTemplateDeleted, ret) - return ret + await helper.postBusEvent(constants.Topics.TimelineTemplateDeleted, items[0]); + return items[0]; } deleteTimelineTemplate.schema = { - timelineTemplateId: Joi.id() -} + timelineTemplateId: Joi.id(), +}; -module.exports = { - searchTimelineTemplates, - createTimelineTemplate, - getTimelineTemplate, - fullyUpdateTimelineTemplate, - partiallyUpdateTimelineTemplate, - deleteTimelineTemplate -} +module.exports.searchTimelineTemplates = searchTimelineTemplates; +module.exports.createTimelineTemplate = createTimelineTemplate; +module.exports.getTimelineTemplate = getTimelineTemplate; +module.exports.fullyUpdateTimelineTemplate = fullyUpdateTimelineTemplate; +module.exports.partiallyUpdateTimelineTemplate = partiallyUpdateTimelineTemplate; +module.exports.deleteTimelineTemplate = deleteTimelineTemplate; -// logger.buildService(module.exports) +logger.buildService(module.exports); diff --git a/test/testHelper.js b/test/testHelper.js index 129fb545..7e637316 100644 --- a/test/testHelper.js +++ b/test/testHelper.js @@ -1,20 +1,20 @@ /** * This file defines common helper methods used for tests */ -const _ = require('lodash') -const uuid = require('uuid/v4') -const config = require('config') -const helper = require('../src/common/helper') -const constants = require('../app-constants') +const _ = require("lodash"); +const uuid = require("uuid/v4"); +const config = require("config"); +const helper = require("../src/common/helper"); +const constants = require("../app-constants"); -const esClient = helper.getESClient() +const esClient = helper.getESClient(); -let challengeType -let phase -let phase2 -let timelineTemplate -let challenge -let completedChallenge +let challengeType; +let phase; +let phase2; +let timelineTemplate; +let challenge; +let completedChallenge; /** * function to deeply compare arrays regardeless of the order @@ -24,164 +24,173 @@ let completedChallenge * @returns {Boolean} The flag indicating whether the arrays have the same content regardless of the order */ const deepCompareArrays = (arr1, arr2) => { - return _(arr1).xorWith(arr2, _.isEqual).isEmpty() -} + return _(arr1).xorWith(arr2, _.isEqual).isEmpty(); +}; /** * Create test data */ -async function createData () { - challengeType = await helper.create('ChallengeType', { +async function createData() { + challengeType = await helper.create("ChallengeType", { id: uuid(), name: `type-${new Date().getTime()}`, - description: 'desc', + description: "desc", isActive: true, - abbreviation: 'abbr', - legacyId: 123 - }) - phase = await helper.create('Phase', { + abbreviation: "abbr", + legacyId: 123, + }); + phase = await helper.create("Phase", { id: uuid(), name: `phase-${new Date().getTime()}`, - description: 'desc', + description: "desc", isOpen: true, - duration: 123 - }) - phase2 = await helper.create('Phase', { + duration: 123, + }); + phase2 = await helper.create("Phase", { id: uuid(), name: `phase2-${new Date().getTime()}`, - description: 'desc', + description: "desc", isOpen: true, - duration: 432 - }) - timelineTemplate = await helper.create('TimelineTemplate', { + duration: 432, + }); + timelineTemplate = await helper.create("TimelineTemplate", { id: uuid(), name: `tt-${new Date().getTime()}`, - description: 'desc', + description: "desc", isActive: true, - phases: [{ - phaseId: phase.id, - defaultDuration: 10000 - }, { - phaseId: phase2.id, - predecessor: phase.id, - defaultDuration: 20000 - }] - }) - const nm = `a B c challenge${new Date().getTime()}` + phases: [ + { + phaseId: phase.id, + defaultDuration: 10000, + }, + { + phaseId: phase2.id, + predecessor: phase.id, + defaultDuration: 20000, + }, + ], + }); + const nm = `a B c challenge${new Date().getTime()}`; const challengeData = { id: uuid(), typeId: challengeType.id, name: nm, - description: 'desc', - metadata: [{ name: nm, value: 'value' }], + description: "desc", + metadata: [{ name: nm, value: "value" }], timelineTemplateId: timelineTemplate.id, phases: [phase], - prizeSets: [{ - type: constants.prizeSetTypes.ChallengePrizes, - description: 'ddd', - prizes: [{ - description: 'some prize', - type: 'type', - value: 800 - }] - }], - tags: ['tag1'], + prizeSets: [ + { + type: constants.prizeSetTypes.ChallengePrizes, + description: "ddd", + prizes: [ + { + description: "some prize", + type: "type", + value: 800, + }, + ], + }, + ], + tags: ["tag1"], projectId: 111, legacy: { - track: 'track', - reviewType: 'Virus Scan', - forumId: 123456 + track: "track", + reviewType: "Virus Scan", + forumId: 123456, }, legacyId: 222, startDate: new Date(), status: constants.challengeStatuses.Active, - groups: ['group1'], - gitRepoURLs: ['https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B'], + groups: ["group1"], + gitRepoURLs: ["https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B"], created: new Date(), - createdBy: 'admin' - } + createdBy: "admin", + }; - challenge = await helper.create('Challenge', challengeData) - completedChallenge = await helper.create('Challenge', _.assign(challengeData, { id: uuid(), status: constants.challengeStatuses.Completed })) + challenge = await helper.create("Challenge", challengeData); + completedChallenge = await helper.create( + "Challenge", + _.assign(challengeData, { id: uuid(), status: constants.challengeStatuses.Completed }) + ); // create challenge in Elasticsearch await esClient.create({ index: config.ES.ES_INDEX, - type: config.ES.ES_TYPE, id: challenge.id, body: _.assignIn({ numOfSubmissions: 0, numOfRegistrants: 0 }, challenge.originalItem()), - refresh: 'true' // refresh ES so that it is visible for read operations instantly - }) + refresh: "true", // refresh ES so that it is visible for read operations instantly + }); // create completedChallenge in Elasticsearch await esClient.create({ index: config.ES.ES_INDEX, - type: config.ES.ES_TYPE, id: completedChallenge.id, - body: _.assignIn({ numOfSubmissions: 0, numOfRegistrants: 0 }, completedChallenge.originalItem()), - refresh: 'true' // refresh ES so that it is visible for read operations instantly - }) + body: _.assignIn( + { numOfSubmissions: 0, numOfRegistrants: 0 }, + completedChallenge.originalItem() + ), + refresh: "true", // refresh ES so that it is visible for read operations instantly + }); } const defaultProjectTerms = [ { - id: '0fcb41d1-ec7c-44bb-8f3b-f017a61cd708', - title: 'Competition Non-Disclosure Agreement', - url: '', - text: 'docusign NDA', - docusignTemplateId: '0c5b7081-1fff-4484-a20f-824c97a03b9b', - agreeabilityType: 'DocuSignable' + id: "0fcb41d1-ec7c-44bb-8f3b-f017a61cd708", + title: "Competition Non-Disclosure Agreement", + url: "", + text: "docusign NDA", + docusignTemplateId: "0c5b7081-1fff-4484-a20f-824c97a03b9b", + agreeabilityType: "DocuSignable", }, { - id: 'be0652ae-8b28-4e91-9b42-8ad00b31e9cb', - title: 'Subcontractor Services Agreement 2009-09-02', - url: 'http://www.topcoder.com/i/terms/Subcontractor+Services+Agreement+2009-09-02.pdf', - text: 'Subcontractor Services Agreement 2009-09-02. This agreement is unavailable in text format. Please download the PDF to read its contents', - agreeabilityType: 'Non-electronically-agreeable' - } -] + id: "be0652ae-8b28-4e91-9b42-8ad00b31e9cb", + title: "Subcontractor Services Agreement 2009-09-02", + url: "http://www.topcoder.com/i/terms/Subcontractor+Services+Agreement+2009-09-02.pdf", + text: "Subcontractor Services Agreement 2009-09-02. This agreement is unavailable in text format. Please download the PDF to read its contents", + agreeabilityType: "Non-electronically-agreeable", + }, +]; -const mockTerms = ['8a0207fc-ac9b-47e7-af1b-81d1ccaf0afc', '453c7c5c-c872-4672-9e78-5162d70903d3'] +const mockTerms = ["8a0207fc-ac9b-47e7-af1b-81d1ccaf0afc", "453c7c5c-c872-4672-9e78-5162d70903d3"]; const additionalTerm = { - id: '28841de8-2f42-486f-beac-21d46a832ab6', - agreeabilityType: 'Electronically-agreeable', - title: '2008 TCO Marathon Match Competition Official Rules', - url: 'http://topcoder.com/mm-terms' -} + id: "28841de8-2f42-486f-beac-21d46a832ab6", + agreeabilityType: "Electronically-agreeable", + title: "2008 TCO Marathon Match Competition Official Rules", + url: "http://topcoder.com/mm-terms", +}; /** * Clear test data */ -async function clearData () { +async function clearData() { // remove challenge in Elasticsearch await esClient.delete({ index: config.ES.ES_INDEX, - type: config.ES.ES_TYPE, id: challenge.id, - refresh: 'true' // refresh ES so that it is effective for read operations instantly - }) + refresh: "true", // refresh ES so that it is effective for read operations instantly + }); // remove completedChallenge in Elasticsearch await esClient.delete({ index: config.ES.ES_INDEX, - type: config.ES.ES_TYPE, id: completedChallenge.id, - refresh: 'true' // refresh ES so that it is effective for read operations instantly - }) - - await challenge.delete() - await completedChallenge.delete() - await timelineTemplate.delete() - await phase.delete() - await phase2.delete() - await challengeType.delete() + refresh: "true", // refresh ES so that it is effective for read operations instantly + }); + + await challenge.delete(); + await completedChallenge.delete(); + await timelineTemplate.delete(); + await phase.delete(); + await phase2.delete(); + await challengeType.delete(); } /** * Get created test data. */ -function getData () { +function getData() { return { challengeType: challengeType.originalItem(), phase: phase.originalItem(), @@ -191,15 +200,15 @@ function getData () { completedChallenge: completedChallenge.originalItem(), defaultProjectTerms, additionalTerm, - mockTerms - } + mockTerms, + }; } /** * Get dates difference in milliseconds */ -function getDatesDiff (d1, d2) { - return new Date(d1).getTime() - new Date(d2).getTime() +function getDatesDiff(d1, d2) { + return new Date(d1).getTime() - new Date(d2).getTime(); } module.exports = { @@ -207,5 +216,5 @@ module.exports = { clearData, getData, getDatesDiff, - deepCompareArrays -} + deepCompareArrays, +}; diff --git a/yarn.lock b/yarn.lock index fceae5d0..938144b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,18 +2,6 @@ # yarn lockfile v1 -"@aws-sdk/service-error-classification@^3.4.1": - version "3.254.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/service-error-classification/-/service-error-classification-3.254.0.tgz#1cf2a2e79fd73d48e751207e25527988dd6716d1" - integrity sha512-8GHqMJBBF9yoMBG/Nf9PusUSMFjG8ygps/cSJPlgcG2vbFn8BCdBZVc4ptXqICZUnBB/6lrxy8nCmNUaru48jg== - -"@aws-sdk/types@^3.4.1": - version "3.254.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.254.0.tgz#760b4a876efa2edcec191dd8b18b989fa717a42e" - integrity sha512-xDEDk6ZAGFO0URPgB6R2mvQANYlojHLjLC9zzOzl07F+uqYS30yZDIg4UFcqPt/x48v7mxlKZpbaZgYI2ZLgGA== - dependencies: - tslib "^2.3.1" - "@babel/code-frame@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" @@ -21,13 +9,14 @@ dependencies: "@babel/highlight" "^7.18.6" -"@babel/generator@^7.20.7", "@babel/generator@^7.4.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.7.tgz#f8ef57c8242665c5929fe2e8d82ba75460187b4a" - integrity sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw== +"@babel/generator@^7.21.3", "@babel/generator@^7.4.0": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.3.tgz#232359d0874b392df04045d72ce2fd9bb5045fce" + integrity sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA== dependencies: - "@babel/types" "^7.20.7" + "@babel/types" "^7.21.3" "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" "@babel/helper-environment-visitor@^7.18.9": @@ -35,13 +24,13 @@ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== -"@babel/helper-function-name@^7.19.0": - version "7.19.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" - integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== +"@babel/helper-function-name@^7.21.0": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz#d552829b10ea9f120969304023cd0645fa00b1b4" + integrity sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg== dependencies: - "@babel/template" "^7.18.10" - "@babel/types" "^7.19.0" + "@babel/template" "^7.20.7" + "@babel/types" "^7.21.0" "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" @@ -76,12 +65,19 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.20.13", "@babel/parser@^7.20.7", "@babel/parser@^7.4.3": - version "7.20.13" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.13.tgz#ddf1eb5a813588d2fb1692b70c6fce75b945c088" - integrity sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw== +"@babel/parser@^7.20.7", "@babel/parser@^7.21.3", "@babel/parser@^7.4.3": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.3.tgz#1d285d67a19162ff9daa358d4cb41d50c06220b3" + integrity sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ== -"@babel/template@^7.18.10", "@babel/template@^7.4.0": +"@babel/runtime@^7.15.4": + version "7.21.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" + integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/template@^7.20.7", "@babel/template@^7.4.0": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== @@ -91,25 +87,25 @@ "@babel/types" "^7.20.7" "@babel/traverse@^7.4.3": - version "7.20.13" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.13.tgz#817c1ba13d11accca89478bd5481b2d168d07473" - integrity sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ== + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.3.tgz#4747c5e7903d224be71f90788b06798331896f67" + integrity sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.20.7" + "@babel/generator" "^7.21.3" "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.19.0" + "@babel/helper-function-name" "^7.21.0" "@babel/helper-hoist-variables" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.20.13" - "@babel/types" "^7.20.7" + "@babel/parser" "^7.21.3" + "@babel/types" "^7.21.3" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.7", "@babel/types@^7.4.0": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" - integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg== +"@babel/types@^7.18.6", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.3", "@babel/types@^7.4.0": + version "7.21.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.3.tgz#4865a5357ce40f64e3400b0f3b737dc6d4f64d05" + integrity sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg== dependencies: "@babel/helper-string-parser" "^7.19.4" "@babel/helper-validator-identifier" "^7.19.1" @@ -129,6 +125,25 @@ enabled "2.0.x" kuler "^2.0.0" +"@grpc/grpc-js@^1.8.0", "@grpc/grpc-js@^1.8.12": + version "1.8.13" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.13.tgz#e775685962909b76f8d4b813833c3d123867165b" + integrity sha512-iY3jsdfbc0ARoCLFvbvUB8optgyb0r1XLPb142u+QtgBcKJYkCIFt3Fd/881KqjLYWjsBJF57N3b8Eop9NDfUA== + dependencies: + "@grpc/proto-loader" "^0.7.0" + "@types/node" ">=12.12.47" + +"@grpc/proto-loader@^0.7.0": + version "0.7.6" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.6.tgz#b71fdf92b184af184b668c4e9395a5ddc23d61de" + integrity sha512-QyAXR8Hyh7uMDmveWxDSUcJr9NAWaZ2I6IXgAYvQmfflwouTM+rArE2eEaCtLlRqO81j7pRLCt81IefUei6Zbw== + dependencies: + "@types/long" "^4.0.1" + lodash.camelcase "^4.3.0" + long "^4.0.0" + protobufjs "^7.0.0" + yargs "^16.2.0" + "@jridgewell/gen-mapping@^0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" @@ -153,7 +168,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": version "0.3.17" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== @@ -161,11 +176,106 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@opensearch-project/opensearch@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@opensearch-project/opensearch/-/opensearch-2.2.0.tgz#2a31a67242bf3bacedc9644a0c68893eb5fb9420" + integrity sha512-E0f2Hooruz9y+17AF69oyyruikVMAEr1TxcQBNEQV4aQnI3o0+6CjqZS+t94SCZdWRTuN7HjIIVGbaYCJDpxgA== + dependencies: + aws4 "^1.11.0" + debug "^4.3.1" + hpagent "^1.2.0" + ms "^2.1.3" + secure-json-parse "^2.4.0" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@topcoder-framework/client-relational@^0.10.13": + version "0.10.13" + resolved "https://topcoder-409275337247.d.codeartifact.us-east-1.amazonaws.com:443/npm/topcoder-framework/@topcoder-framework/client-relational/-/client-relational-0.10.13.tgz#84293cd265328d5f770c28ffd690fbb434ac936b" + integrity sha512-p4ygOE0K2xrz/wmTSS5/3DX2lEH/bmiWsW+sL8RVstAhilWSQmdyJb49sI/QzbFqhHGS/aQnkKPt8gaNtIaVWQ== + dependencies: + "@grpc/grpc-js" "^1.8.0" + "@topcoder-framework/lib-common" "^0.10.13" + topcoder-interface "github:topcoder-platform/plat-interface-definition#v0.0.46" + tslib "^2.4.1" + +"@topcoder-framework/domain-challenge@^0.10.13": + version "0.10.13" + resolved "https://topcoder-409275337247.d.codeartifact.us-east-1.amazonaws.com:443/npm/topcoder-framework/@topcoder-framework/domain-challenge/-/domain-challenge-0.10.13.tgz#dede4cd01054e56eb4e4486eeb99cfd9ab4d75f1" + integrity sha512-srkncIcHaD1aGYD6DSHGzZDORjPZkTN9qNgZSNNYXx3Q6pNc4z3dUQqv79bEv472af4zkXmemMcmHqPTRilVtQ== + dependencies: + "@grpc/grpc-js" "^1.8.0" + "@topcoder-framework/client-relational" "^0.10.13" + "@topcoder-framework/lib-common" "^0.10.13" + topcoder-interface "github:topcoder-platform/plat-interface-definition#v0.0.46" + tslib "^2.4.1" + +"@topcoder-framework/lib-common@^0.10.13": + version "0.10.13" + resolved "https://topcoder-409275337247.d.codeartifact.us-east-1.amazonaws.com:443/npm/topcoder-framework/@topcoder-framework/lib-common/-/lib-common-0.10.13.tgz#69a0c70d601cc37821ece1b13d300dbe8e6ddc10" + integrity sha512-LXaoLQma+7cs7ly6McXmhO3YWNF27MzqiR3fgtlefVU1XbfVfWhSfDLitTUSw08PMgv+VC6nTfyo0t4202ZVcg== + dependencies: + "@grpc/grpc-js" "^1.8.0" + rimraf "^3.0.2" + topcoder-interface "github:topcoder-platform/plat-interface-definition#v0.0.46" + tslib "^2.4.1" + "@types/body-parser@*": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -179,13 +289,6 @@ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.4.tgz#e913e8175db8307d78b4e8fa690408ba6b65dee4" integrity sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw== -"@types/cls-hooked@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@types/cls-hooked/-/cls-hooked-4.3.3.tgz#c09e2f8dc62198522eaa18a5b6b873053154bd00" - integrity sha512-gNstDTb/ty5h6gJd6YpSPgsLX9LmRpaKJqGFp7MRlYxhwp4vXXKlJ9+bt1TZ9KbVNXE+Mbxy2AYXcpY21DDtJw== - dependencies: - "@types/node" "*" - "@types/connect@*": version "3.4.35" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" @@ -206,10 +309,10 @@ "@types/express" "*" "@types/express-unless" "*" -"@types/express-serve-static-core@^4.17.31": - version "4.17.32" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz#93dda387f5516af616d8d3f05f2c4c79d81e1b82" - integrity sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA== +"@types/express-serve-static-core@^4.17.33": + version "4.17.33" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz#de35d30a9d637dc1450ad18dd583d75d5733d543" + integrity sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA== dependencies: "@types/node" "*" "@types/qs" "*" @@ -223,46 +326,35 @@ express-unless "*" "@types/express@*": - version "4.17.15" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.15.tgz#9290e983ec8b054b65a5abccb610411953d417ff" - integrity sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ== + version "4.17.17" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" + integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== dependencies: "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.31" + "@types/express-serve-static-core" "^4.17.33" "@types/qs" "*" "@types/serve-static" "*" +"@types/long@^4.0.1": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a" + integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== + "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== -"@types/mysql@*": - version "2.15.21" - resolved "https://registry.yarnpkg.com/@types/mysql/-/mysql-2.15.21.tgz#7516cba7f9d077f980100c85fd500c8210bd5e45" - integrity sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg== - dependencies: - "@types/node" "*" - -"@types/node@*": - version "18.11.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" - integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== +"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0": + version "18.15.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.6.tgz#af98ef4a36e7ac5f2d03040f3109fcce972bf6cb" + integrity sha512-YErOafCZpK4g+Rp3Q/PBgZNAsWKGunQTm9FA3/Pbcm0VCriTEzcrutQ/SxSc0rytAp0NoFWue669jmKhEtd0sA== "@types/node@11.11.0": version "11.11.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.0.tgz#070e9ce7c90e727aca0e0c14e470f9a93ffe9390" integrity sha512-D5Rt+HXgEywr3RQJcGlZUCTCx1qVbCZpVk3/tOOA6spLNZdGm8BU+zRgdRYDoF1pO3RuXLxADzMrF903JlQXqg== -"@types/pg@*": - version "8.6.6" - resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.6.6.tgz#21cdf873a3e345a6e78f394677e3b3b1b543cb80" - integrity sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw== - dependencies: - "@types/node" "*" - pg-protocol "*" - pg-types "^2.2.0" - "@types/qs@*": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -274,9 +366,9 @@ integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== "@types/serve-static@*": - version "1.15.0" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.0.tgz#c7930ff61afb334e121a9da780aac0d9b8f34155" - integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== + version "1.15.1" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.1.tgz#86b1753f0be4f9a1bee68d459fcda5be4ea52b5d" + integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ== dependencies: "@types/mime" "*" "@types/node" "*" @@ -289,6 +381,16 @@ "@types/cookiejar" "*" "@types/node" "*" +"@types/triple-beam@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.2.tgz#38ecb64f01aa0d02b7c8f4222d7c38af6316fef8" + integrity sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -297,16 +399,6 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-jsx@^5.0.0: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -acorn@^6.0.2: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -321,12 +413,7 @@ agentkeepalive@^3.4.1: dependencies: humanize-ms "^1.2.1" -ajv-keywords@^3.0.0: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv@^6.0.1, ajv@^6.12.3, ajv@^6.5.0: +ajv@^6.12.3: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -341,11 +428,6 @@ ansi-colors@3.2.3: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -361,6 +443,11 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -373,6 +460,21 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + append-transform@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-1.0.0.tgz#046a52ae582a228bd72f58acfbe2967c678759ab" @@ -392,22 +494,19 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -array-includes@^3.0.3, array-includes@^3.1.1: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" - is-string "^1.0.7" - array.prototype.reduce@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz#6b20b0daa9d9734dd6bc7ea66b5bbce395471eac" @@ -436,13 +535,6 @@ assertion-error@^1.1.0: resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -async-hook-jl@^1.7.6: - version "1.7.6" - resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" - integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== - dependencies: - stack-chain "^1.3.7" - async@^3.2.3: version "3.2.4" resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" @@ -453,11 +545,6 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -atomic-batcher@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/atomic-batcher/-/atomic-batcher-1.0.2.tgz#d16901d10ccec59516c197b9ccd8930689b813b4" - integrity sha512-EFGCRj4kLX1dHv1cDzTk+xbjBFj1GnJDpui52YmEcxxHHEWjYyT6l51U7n6WQ28osZH4S9gSybxe56Vm7vB61Q== - available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" @@ -479,9 +566,9 @@ aws-sdk@2.395.0: xml2js "0.4.19" aws-sdk@^2.1145.0: - version "2.1299.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1299.0.tgz#493254104af5b9aaee0d7cd9150611d137e4f205" - integrity sha512-xTh6pmCUEJljkFfTM3sE8UozDxal80uX/5WZl8GcjQ+NbrGeQEdvL6wFWBwEEVbhR0VBVuU37cKPuQlfENbRYA== + version "2.1342.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1342.0.tgz#2ddb60e7480b6f3a3b1ec5cfba4c6beed7cfc024" + integrity sha512-RknStRPY+ohgOhuuDYEkAWuBcU9841EjtelZn4J2VubhaS7ZFQ2lmiYqm4P5Tw8Kwq6GuUqISBB8RCp8cO2qfA== dependencies: buffer "4.9.2" events "1.1.1" @@ -499,54 +586,19 @@ aws-sign2@~0.7.0: resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== -aws-xray-sdk-core@3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/aws-xray-sdk-core/-/aws-xray-sdk-core-3.4.1.tgz#25592b7e4ed3ebd25ece9c1f258d3f68558e1ab6" - integrity sha512-HPQ+9GMF+yhDDXNKPp6HGAIv2yVapKTI7WRs2aN3TT+RxQkbmgO+3JlcMvRL2/lu0RqTVWoYCIhmF9/H/zRL1A== - dependencies: - "@aws-sdk/service-error-classification" "^3.4.1" - "@aws-sdk/types" "^3.4.1" - "@types/cls-hooked" "^4.3.3" - atomic-batcher "^1.0.2" - cls-hooked "^4.2.2" - semver "^5.3.0" - -aws-xray-sdk-express@3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/aws-xray-sdk-express/-/aws-xray-sdk-express-3.4.1.tgz#e958976db0631b93feaea5db38979f461baea707" - integrity sha512-c8efb0ywsvzcqXT0PLbaAG0nMgpbzGu9FOagm569Ic/GMJwglACVAxsHJ3e3fYlRDbq2q6U0QhadqGb4MOa9YQ== - dependencies: - "@types/express" "*" - -aws-xray-sdk-mysql@3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/aws-xray-sdk-mysql/-/aws-xray-sdk-mysql-3.4.1.tgz#8f2eab61f020953742d09a42a96994e08028ba75" - integrity sha512-k2UczelWpBqNZfnG4+czoLDzhxzcvvZXBjvriVTokdXcNknCRG4lBCnSOh/RdvLq62SDaCwmv5c67B3NObfXbg== - dependencies: - "@types/mysql" "*" - -aws-xray-sdk-postgres@3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/aws-xray-sdk-postgres/-/aws-xray-sdk-postgres-3.4.1.tgz#5a24e36d6520186ab9b2e6af5724ee463d2117ea" - integrity sha512-3+qfZD8BttjOQ4jzsuRYJzDPOu4dl4nXZPPijAlLUZC978gFIOAWMqJZE6cDmOjXs2BVYdCW8wfiJ1NPYbesBw== - dependencies: - "@types/pg" "*" - -aws-xray-sdk@^3.3.8: - version "3.4.1" - resolved "https://registry.yarnpkg.com/aws-xray-sdk/-/aws-xray-sdk-3.4.1.tgz#e8991e71ce0b7c89d3c3a54c445209eee27a3c71" - integrity sha512-7iz+svMi47EBW3hCGLoMvXYDTG065gg+pdgk/CYXfx0EW9N+uCovKCQodfIwFAMSQ6P4bMxw6jD30h+XtMeTgQ== - dependencies: - aws-xray-sdk-core "3.4.1" - aws-xray-sdk-express "3.4.1" - aws-xray-sdk-mysql "3.4.1" - aws-xray-sdk-postgres "3.4.1" - -aws4@^1.8.0: +aws4@^1.11.0, aws4@^1.8.0: version "1.12.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== +axios-retry@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.4.0.tgz#f464dbe9408e5aa78fa319afd38bb69b533d8854" + integrity sha512-VdgaP+gHH4iQYCCNUWF2pcqeciVOdGrBBAYUfTY+wPcO5Ltvp/37MLFNCmJKo7Gj3SHvCSdL8ouI1qLYJN3liA== + dependencies: + "@babel/runtime" "^7.15.4" + is-retry-allowed "^2.2.0" + axios@^0.19.0: version "0.19.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" @@ -561,15 +613,6 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" -babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g== - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - babel-runtime@6.6.1: version "6.6.1" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.6.1.tgz#788b94b6f634e25b91bd6c5df72d467457afb000" @@ -601,12 +644,17 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + bluebird@^3.5.1: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -body-parser@1.20.1, body-parser@^1.15.1: +body-parser@1.20.1: version "1.20.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== @@ -624,6 +672,24 @@ body-parser@1.20.1, body-parser@^1.15.1: type-is "~1.6.18" unpipe "1.0.0" +body-parser@^1.15.1: + version "1.20.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -632,6 +698,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -700,18 +773,6 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - integrity sha512-UJiE1otjXPF5/x+T3zTnSFiTOEmJoGTD9HmBoxnCUwho61a2eSNn/VwtwuIBDAo2SEOv1AJ7ARI5gCmohFLu/g== - dependencies: - callsites "^0.2.0" - -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - integrity sha512-Zv4Dns9IbXXmPkgRRUjAaJQgfN4xX5p6+RQFhWUqscdvvK2xK/ZL8b3IXIJsj+4sD+f24NwnWy2BY8AJ82JB0A== - camelcase@^5.0.0: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -748,7 +809,7 @@ chai@^4.2.0: pathval "^1.1.1" type-detect "^4.0.5" -chalk@^1.0.0, chalk@^1.1.3: +chalk@^1.0.0: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== @@ -759,7 +820,7 @@ chalk@^1.0.0, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: +chalk@^2.0.0, chalk@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -768,32 +829,25 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - integrity sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg== - check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw== - dependencies: - restore-cursor "^2.0.0" - -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== +chokidar@^3.5.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" cliui@^5.0.0: version "5.0.0" @@ -804,20 +858,20 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone@2.x: version "2.1.2" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== -cls-hooked@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" - integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== - dependencies: - async-hook-jl "^1.7.6" - emitter-listener "^1.0.1" - semver "^5.4.1" - codependency@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/codependency/-/codependency-0.1.4.tgz#d1763ab7264bd70c91d9626e98862d3792bf8d4a" @@ -832,12 +886,19 @@ color-convert@^1.9.0, color-convert@^1.9.3: dependencies: color-name "1.1.3" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -color-name@^1.0.0: +color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== @@ -900,11 +961,6 @@ config@^3.0.1: dependencies: json5 "^2.2.3" -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha512-OKZnPGeMQy2RPaUIBPFFd71iNf4791H12MCRuVQDnzGRwCYNYmTDy5pdafo2SLAcEMKzTOQnLWG4QdcjeJUMEg== - content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -912,10 +968,10 @@ content-disposition@0.5.4: dependencies: safe-buffer "5.2.1" -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== convert-source-map@^1.6.0: version "1.9.0" @@ -979,17 +1035,6 @@ cross-spawn@^4: lru-cache "^4.0.1" which "^1.2.9" -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - cssfilter@0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" @@ -1002,12 +1047,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug-log@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" - integrity sha512-gV/pe1YIaKNgLYnd1g9VNW80tcb7oV5qvNUxG7NM8rbDpnl6RGunzlAtlGSb0wEs3nesu2vHNiX9TSsZ+Y+RjA== - -debug@2.6.9, debug@^2.2.0, debug@^2.6.8: +debug@2.6.9, debug@^2.2.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -1021,7 +1061,7 @@ debug@3.2.6: dependencies: ms "^2.1.1" -debug@4, debug@^4.1.0, debug@^4.1.1: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1066,10 +1106,28 @@ deep-equal@1.0.1: resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" integrity sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw== -deep-is@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deep-equal@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.0.tgz#5caeace9c781028b9ff459f33b779346637c43e6" + integrity sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw== + dependencies: + call-bind "^1.0.2" + es-get-iterator "^1.1.2" + get-intrinsic "^1.1.3" + is-arguments "^1.1.1" + is-array-buffer "^3.0.1" + is-date-object "^1.0.5" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + isarray "^2.0.5" + object-is "^1.1.5" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + side-channel "^1.0.4" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.1" + which-typed-array "^1.1.9" default-require-extensions@^2.0.0: version "2.0.0" @@ -1079,25 +1137,13 @@ default-require-extensions@^2.0.0: strip-bom "^3.0.0" define-properties@^1.1.2, define-properties@^1.1.3, define-properties@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + version "1.2.0" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" + integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== dependencies: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -deglob@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/deglob/-/deglob-2.1.1.tgz#d268e168727799862e8eac07042e165957c1f3be" - integrity sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw== - dependencies: - find-root "^1.0.0" - glob "^7.0.5" - ignore "^3.0.9" - pkg-config "^1.1.0" - run-parallel "^1.1.2" - uniq "^1.0.1" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -1118,21 +1164,6 @@ diff@3.5.0: resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg== - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - dotenv@^8.2.0: version "8.6.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" @@ -1178,7 +1209,7 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -elasticsearch@^16.1.1: +elasticsearch@^16.7.3: version "16.7.3" resolved "https://registry.yarnpkg.com/elasticsearch/-/elasticsearch-16.7.3.tgz#bf0e1cc129ab2e0f06911953a1b1f3c740715fab" integrity sha512-e9kUNhwnIlu47fGAr4W6yZJbkpsgQJB0TqNK8rCANe1J4P65B1sGnbCFTgcKY3/dRgCWnuP1AJ4obvzW604xEQ== @@ -1187,18 +1218,16 @@ elasticsearch@^16.1.1: chalk "^1.0.0" lodash "^4.17.10" -emitter-listener@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" - integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== - dependencies: - shimmer "^1.2.0" - emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + enabled@2.0.x: version "2.0.0" resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" @@ -1209,7 +1238,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -error-ex@^1.2.0, error-ex@^1.3.1: +error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== @@ -1217,17 +1246,17 @@ error-ex@^1.2.0, error-ex@^1.3.1: is-arrayish "^0.2.1" es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" - integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== + version "1.21.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== dependencies: + array-buffer-byte-length "^1.0.0" available-typed-arrays "^1.0.5" call-bind "^1.0.2" es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" - function-bind "^1.1.1" function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.0" get-symbol-description "^1.0.0" globalthis "^1.0.3" gopd "^1.0.1" @@ -1235,8 +1264,8 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: has-property-descriptors "^1.0.0" has-proto "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.4" - is-array-buffer "^3.0.1" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" is-callable "^1.2.7" is-negative-zero "^2.0.2" is-regex "^1.1.4" @@ -1244,11 +1273,12 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: is-string "^1.0.7" is-typed-array "^1.1.10" is-weakref "^1.0.2" - object-inspect "^1.12.2" + object-inspect "^1.12.3" object-keys "^1.1.1" object.assign "^4.1.4" regexp.prototype.flags "^1.4.3" safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" string.prototype.trimend "^1.0.6" string.prototype.trimstart "^1.0.6" typed-array-length "^1.0.4" @@ -1260,6 +1290,21 @@ es-array-method-boxes-properly@^1.0.0: resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== +es-get-iterator@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + has-symbols "^1.0.3" + is-arguments "^1.1.1" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.7" + isarray "^2.0.5" + stop-iteration-iterator "^1.0.0" + es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -1283,6 +1328,11 @@ es6-error@^4.0.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -1293,196 +1343,11 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== -eslint-config-standard-jsx@6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-6.0.2.tgz#90c9aa16ac2c4f8970c13fc7efc608bacd02da70" - integrity sha512-D+YWAoXw+2GIdbMBRAzWwr1ZtvnSf4n4yL0gKGg7ShUOGXkSOLerI17K4F6LdQMJPNMoWYqepzQD/fKY+tXNSg== - -eslint-config-standard@12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz#638b4c65db0bd5a41319f96bba1f15ddad2107d9" - integrity sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ== - -eslint-import-resolver-node@^0.3.1: - version "0.3.7" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" - integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== - dependencies: - debug "^3.2.7" - is-core-module "^2.11.0" - resolve "^1.22.1" - -eslint-module-utils@^2.2.0: - version "2.7.4" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" - integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== - dependencies: - debug "^3.2.7" - -eslint-plugin-es@^1.3.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-1.4.1.tgz#12acae0f4953e76ba444bfd1b2271081ac620998" - integrity sha512-5fa/gR2yR3NxQf+UXkeLeP8FBBl6tSgdrAz1+cF84v1FMM4twGwQoqTnn+QxFLcPOrF4pdKEJKDB/q9GoyJrCA== - dependencies: - eslint-utils "^1.4.2" - regexpp "^2.0.1" - -eslint-plugin-import@~2.14.0: - version "2.14.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz#6b17626d2e3e6ad52cfce8807a845d15e22111a8" - integrity sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g== - dependencies: - contains-path "^0.1.0" - debug "^2.6.8" - doctrine "1.5.0" - eslint-import-resolver-node "^0.3.1" - eslint-module-utils "^2.2.0" - has "^1.0.1" - lodash "^4.17.4" - minimatch "^3.0.3" - read-pkg-up "^2.0.0" - resolve "^1.6.0" - -eslint-plugin-node@~7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz#a6e054e50199b2edd85518b89b4e7b323c9f36db" - integrity sha512-lfVw3TEqThwq0j2Ba/Ckn2ABdwmL5dkOgAux1rvOk6CO7A6yGyPI2+zIxN6FyNkp1X1X/BSvKOceD6mBWSj4Yw== - dependencies: - eslint-plugin-es "^1.3.1" - eslint-utils "^1.3.1" - ignore "^4.0.2" - minimatch "^3.0.4" - resolve "^1.8.1" - semver "^5.5.0" - -eslint-plugin-promise@~4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz#2d074b653f35a23d1ba89d8e976a985117d1c6a2" - integrity sha512-Si16O0+Hqz1gDHsys6RtFRrW7cCTB6P7p3OJmKp3Y3dxpQE2qwOA7d3xnV+0mBmrPoi0RBnxlCKvqu70te6wjg== - -eslint-plugin-react@~7.11.1: - version "7.11.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz#c01a7af6f17519457d6116aa94fc6d2ccad5443c" - integrity sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw== - dependencies: - array-includes "^3.0.3" - doctrine "^2.1.0" - has "^1.0.3" - jsx-ast-utils "^2.0.1" - prop-types "^15.6.2" - -eslint-plugin-standard@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.2.tgz#021211a9f077e63a6847e7bb9ab4247327ac8e0c" - integrity sha512-nKptN8l7jksXkwFk++PhJB3cCDTcXOEyhISIN86Ue2feJ1LFyY3PrY3/xT2keXlJSY5bpmbiTG0f885/YKAvTA== - -eslint-scope@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" - integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-utils@^1.3.1, eslint-utils@^1.4.2: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint@~5.4.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.4.0.tgz#d068ec03006bb9e06b429dc85f7e46c1b69fac62" - integrity sha512-UIpL91XGex3qtL6qwyCQJar2j3osKxK9e3ano3OcGEIRM4oWIpCkDg9x95AXEC2wMs7PnxzOkPZ2gq+tsMS9yg== - dependencies: - ajv "^6.5.0" - babel-code-frame "^6.26.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^3.1.0" - doctrine "^2.1.0" - eslint-scope "^4.0.0" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^4.0.0" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^2.0.0" - functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" - ignore "^4.0.2" - imurmurhash "^0.1.4" - inquirer "^5.2.0" - is-resolvable "^1.1.0" - js-yaml "^3.11.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.5" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" - pluralize "^7.0.0" - progress "^2.0.0" - regexpp "^2.0.0" - require-uncached "^1.0.3" - semver "^5.5.0" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" - table "^4.0.3" - text-table "^0.2.0" - -espree@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-4.1.0.tgz#728d5451e0fd156c04384a7ad89ed51ff54eb25f" - integrity sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w== - dependencies: - acorn "^6.0.2" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" - esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.0.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" @@ -1554,15 +1419,6 @@ extend@^3.0.0, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" - integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -1583,30 +1439,17 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - fecha@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - integrity sha512-uXP/zGzxxFvFfcZGgBIwotm+Tdc55ddPAzF7iHshP4YGaXMww7rSF9peD9D1sui5ebONg5UobsZv+FfgEpGv/w== +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" + to-regex-range "^5.0.1" finalhandler@1.2.0: version "1.2.0" @@ -1630,11 +1473,6 @@ find-cache-dir@^2.1.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-root@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - find-up@3.0.0, find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -1642,23 +1480,6 @@ find-up@3.0.0, find-up@^3.0.0: dependencies: locate-path "^3.0.0" -find-up@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== - dependencies: - locate-path "^2.0.0" - -flat-cache@^1.2.1: - version "1.3.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f" - integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg== - dependencies: - circular-json "^0.3.1" - graceful-fs "^4.1.2" - rimraf "~2.6.2" - write "^0.2.1" - flat@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b" @@ -1741,6 +1562,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -1756,17 +1582,12 @@ function.prototype.name@^1.1.5: es-abstract "^1.19.0" functions-have-names "^1.2.2" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== - functions-have-names@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -get-caller-file@^2.0.1: +get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -1776,7 +1597,7 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== @@ -1790,11 +1611,6 @@ get-parameter-names@^0.3.0: resolved "https://registry.yarnpkg.com/get-parameter-names/-/get-parameter-names-0.3.0.tgz#2d2237cd592e6c5b859ab2efdab435f008e5bb97" integrity sha512-KkR1dX7U1TynXFkqveVE/XoRn9qRAsM2q4Eu2WsGTFzoaSdnNQEfxbcK+LMv8DcFoQQT9BFjNL+bf9ZyTLkWpg== -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -1810,6 +1626,13 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + glob@7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -1833,7 +1656,7 @@ glob@^6.0.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.5, glob@^7.1.2, glob@^7.1.3: +glob@^7.0.5, glob@^7.1.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -1845,7 +1668,7 @@ glob@^7.0.5, glob@^7.1.2, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^11.1.0, globals@^11.7.0: +globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== @@ -1865,9 +1688,9 @@ gopd@^1.0.1: get-intrinsic "^1.1.3" graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: - version "4.2.10" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== growl@1.10.5: version "1.10.5" @@ -1928,7 +1751,7 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has@^1.0.1, has@^1.0.3: +has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== @@ -1967,6 +1790,11 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== +hpagent@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-1.2.0.tgz#0ae417895430eb3770c03443456b8d90ca464903" + integrity sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA== + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -2026,7 +1854,7 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -iconv-lite@0.4.24, iconv-lite@^0.4.17: +iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -2048,15 +1876,10 @@ ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^3.0.9: - version "3.3.10" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== - -ignore@^4.0.2: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore-by-default@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== imurmurhash@^0.1.4: version "0.1.4" @@ -2076,31 +1899,12 @@ inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inquirer@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" - integrity sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.1.0" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^5.5.2" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - -internal-slot@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3" - integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ== +internal-slot@^1.0.4, internal-slot@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== dependencies: - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.0" has "^1.0.3" side-channel "^1.0.4" @@ -2114,7 +1918,7 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -is-arguments@^1.0.4: +is-arguments@^1.0.4, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== @@ -2122,13 +1926,13 @@ is-arguments@^1.0.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-array-buffer@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a" - integrity sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ== +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.0" is-typed-array "^1.1.10" is-arrayish@^0.2.1: @@ -2148,6 +1952,13 @@ is-bigint@^1.0.1: dependencies: has-bigints "^1.0.1" +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-boolean-object@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" @@ -2166,25 +1977,35 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.11.0, is-core-module@^2.9.0: +is-core-module@^2.9.0: version "2.11.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== dependencies: has "^1.0.3" -is-date-object@^1.0.1: +is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== dependencies: has-tostringtag "^1.0.0" +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + is-generator-function@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" @@ -2192,6 +2013,13 @@ is-generator-function@^1.0.7: dependencies: has-tostringtag "^1.0.0" +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-ip@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-2.0.0.tgz#68eea07e8a0a0a94c2d080dd674c731ab2a461ab" @@ -2199,6 +2027,11 @@ is-ip@^2.0.0: dependencies: ip-regex "^2.0.0" +is-map@^2.0.1, is-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" + integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -2211,6 +2044,11 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -2219,10 +2057,15 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-resolvable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== +is-retry-allowed@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" + integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== + +is-set@^2.0.1, is-set@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" + integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== is-shared-array-buffer@^1.0.2: version "1.0.2" @@ -2271,6 +2114,11 @@ is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== +is-weakmap@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" + integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== + is-weakref@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" @@ -2278,11 +2126,24 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +is-weakset@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" + integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isemail@3.x.x: version "3.2.0" resolved "https://registry.yarnpkg.com/isemail/-/isemail-3.2.0.tgz#59310a021931a9fb06bbb51e155ce0b3f236832c" @@ -2380,16 +2241,11 @@ joi@^14.0.0: isemail "3.x.x" topo "3.x.x" -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg== - js-yaml@3.13.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" @@ -2398,7 +2254,7 @@ js-yaml@3.13.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.11.0, js-yaml@^3.13.1: +js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -2431,11 +2287,6 @@ json-schema@0.4.0: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - json-stringify-safe@5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -2472,14 +2323,6 @@ jsprim@^1.2.2: json-schema "0.4.0" verror "1.10.0" -jsx-ast-utils@^2.0.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e" - integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w== - dependencies: - array-includes "^3.1.1" - object.assign "^4.1.0" - jwa@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" @@ -2518,29 +2361,11 @@ kuler@^2.0.0: resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - limiter@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2" integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA== -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ== - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -2551,14 +2376,6 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -2567,6 +2384,11 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -2617,7 +2439,7 @@ lodash@4.17.15: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== -lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0: +lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.19: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -2630,22 +2452,26 @@ log-symbols@2.2.0: chalk "^2.0.1" logform@^2.3.2, logform@^2.4.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/logform/-/logform-2.4.2.tgz#a617983ac0334d0c3b942c34945380062795b47c" - integrity sha512-W4c9himeAwXEdZ05dQNerhFz2XG80P9Oj0loPUMV23VC2it0orMHQhJm4hdnnor3rd1HsGf6a2lPwBM1zeXHGw== + version "2.5.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.5.1.tgz#44c77c34becd71b3a42a3970c77929e52c6ed48b" + integrity sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg== dependencies: "@colors/colors" "1.5.0" + "@types/triple-beam" "^1.3.2" fecha "^4.2.0" ms "^2.1.1" safe-stable-stringify "^2.3.1" triple-beam "^1.3.0" -loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + +long@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.1.tgz#e27595d0083d103d2fa2c20c7699f8e0c92b897f" + integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A== loupe@^2.3.1: version "2.3.6" @@ -2671,9 +2497,9 @@ lru-cache@~4.0.0: yallist "^2.0.0" lru-memoizer@^2.1.2: - version "2.1.4" - resolved "https://registry.yarnpkg.com/lru-memoizer/-/lru-memoizer-2.1.4.tgz#b864d92b557f00b1eeb322156a0409cb06dafac6" - integrity sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/lru-memoizer/-/lru-memoizer-2.2.0.tgz#b9d90c91637b4b1a423ef76f3156566691293df8" + integrity sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw== dependencies: lodash.clonedeep "^4.5.0" lru-cache "~4.0.0" @@ -2730,12 +2556,7 @@ mime@1.6.0, mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -"minimatch@2 || 3", minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1: +"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -2749,10 +2570,10 @@ minimatch@3.0.4: dependencies: brace-expansion "^1.1.7" -minimist@^1.1.0, minimist@^1.2.5, minimist@^1.2.6: - version "1.2.7" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" - integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +minimist@^1.2.5, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== mkdirp@0.5.4: version "0.5.4" @@ -2761,7 +2582,7 @@ mkdirp@0.5.4: dependencies: minimist "^1.2.5" -mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: +mkdirp@^0.5.0, mkdirp@~0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -2822,16 +2643,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.2: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.2, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ== - mv@~2: version "2.1.1" resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" @@ -2846,11 +2662,6 @@ nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - ncp@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" @@ -2866,11 +2677,6 @@ nested-error-stacks@^2.0.0: resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - node-cache@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d" @@ -2886,6 +2692,29 @@ node-environment-flags@1.0.5: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" +nodemon@^2.0.20: + version "2.0.22" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.22.tgz#182c45c3a78da486f673d6c1702e00728daf5258" + integrity sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ== + dependencies: + chokidar "^3.5.2" + debug "^3.2.7" + ignore-by-default "^1.0.1" + minimatch "^3.1.2" + pstree.remy "^1.1.8" + semver "^5.7.1" + simple-update-notifier "^1.0.7" + supports-color "^5.5.0" + touch "^3.1.0" + undefsafe "^2.0.5" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg== + dependencies: + abbrev "1" + normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -2896,6 +2725,11 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + nyc@^14.0.0: version "14.1.1" resolved "https://registry.yarnpkg.com/nyc/-/nyc-14.1.1.tgz#151d64a6a9f9f5908a1b73233931e4a0a3075eeb" @@ -2932,16 +2766,24 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1: +object-assign@^4: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.2, object-inspect@^1.9.0: +object-inspect@^1.12.3, object-inspect@^1.9.0: version "1.12.3" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-is@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.0.11, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -2962,7 +2804,7 @@ object.assign@4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" -object.assign@^4.1.0, object.assign@^4.1.4: +object.assign@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== @@ -3003,42 +2845,11 @@ one-time@^1.0.0: dependencies: fn.name "1.x.x" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== - dependencies: - mimic-fn "^1.0.0" - -optionator@^0.8.2: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== - -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -3046,13 +2857,6 @@ p-limit@^2.0.0: dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== - dependencies: - p-limit "^1.1.0" - p-locate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" @@ -3060,11 +2864,6 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -3080,13 +2879,6 @@ package-hash@^3.0.0: lodash.flattendeep "^4.4.0" release-zalgo "^1.0.0" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ== - dependencies: - error-ex "^1.2.0" - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -3110,16 +2902,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-is-inside@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== - -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -3130,13 +2912,6 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ== - dependencies: - pify "^2.0.0" - path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -3154,31 +2929,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== -pg-int8@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" - integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== - -pg-protocol@*: - version "1.5.0" - resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" - integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== - -pg-types@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" - integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== - dependencies: - pg-int8 "1.0.1" - postgres-array "~2.0.0" - postgres-bytea "~1.0.0" - postgres-date "~1.0.4" - postgres-interval "^1.1.0" - -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^3.0.0: version "3.0.0" @@ -3190,23 +2944,6 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pkg-conf@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" - integrity sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g== - dependencies: - find-up "^2.0.0" - load-json-file "^4.0.0" - -pkg-config@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pkg-config/-/pkg-config-1.1.1.tgz#557ef22d73da3c8837107766c52eadabde298fe4" - integrity sha512-ft/WI9YK6FuTuw4Ql+QUaNXtm/ASQNqDUUsZEgFZKyFpW6amyP8Gx01xrRs8KdiNbbqXfYxkOXplpq1euWbOjw== - dependencies: - debug-log "^1.0.0" - find-root "^1.0.0" - xtend "^4.0.1" - pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -3214,61 +2951,38 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== - -postgres-array@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" - integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== - -postgres-bytea@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" - integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== - -postgres-date@~1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" - integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== - -postgres-interval@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" - integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== - dependencies: - xtend "^4.0.0" - precond@0.2: version "0.2.3" resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" integrity sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ== -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== +prettier@^2.8.1: + version "2.8.6" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.6.tgz#5c174b29befd507f14b83e3c19f83fdc0e974b71" + integrity sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ== process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -prop-types@^15.6.2: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" +protobufjs@^7.0.0: + version "7.2.2" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.2.tgz#2af401d8c547b9476fb37ffc65782cf302342ca3" + integrity sha512-++PrQIjrom+bFDPpfmqXfAGSQs40116JRrqqyf53dymUMvvb5d/LMRyicRoF1AUKoXVS1/IgJXlEgcpr4gTF3Q== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" proxy-addr@~2.0.7: version "2.0.7" @@ -3293,6 +3007,11 @@ psl@^1.1.28: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +pstree.remy@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" + integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -3308,13 +3027,20 @@ q@1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@6.11.0, qs@^6.5.1: +qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" +qs@^6.5.1: + version "6.11.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.1.tgz#6c29dff97f0c0060765911ba65cbc9764186109f" + integrity sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ== + dependencies: + side-channel "^1.0.4" + qs@~6.5.2: version "6.5.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" @@ -3325,11 +3051,6 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - r7insight_node@^1.8.4: version "1.8.4" resolved "https://registry.yarnpkg.com/r7insight_node/-/r7insight_node-1.8.4.tgz#875633032137545b3cc7c80763baf09f6ba66801" @@ -3357,18 +3078,15 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" -react-is@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w== +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" read-pkg-up@^4.0.0: version "4.0.0" @@ -3378,15 +3096,6 @@ read-pkg-up@^4.0.0: find-up "^3.0.0" read-pkg "^3.0.0" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA== - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -3397,9 +3106,9 @@ read-pkg@^3.0.0: path-type "^3.0.0" readable-stream@^2.3.5: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -3410,14 +3119,21 @@ readable-stream@^2.3.5: util-deprecate "~1.0.1" readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + reconnect-core@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/reconnect-core/-/reconnect-core-1.3.0.tgz#fbae52919a7877d844e3246d01a2f26701c833c8" @@ -3425,6 +3141,11 @@ reconnect-core@1.3.0: dependencies: backoff "~2.5.0" +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" @@ -3434,11 +3155,6 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.1.3" functions-have-names "^1.2.2" -regexpp@^2.0.0, regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - release-zalgo@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/release-zalgo/-/release-zalgo-1.0.0.tgz#09700b7e5074329739330e535c5a90fb67851730" @@ -3482,25 +3198,12 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - integrity sha512-Xct+41K3twrbBHdxAgMoOS+cNcoqIjfM2/VxBF4LL2hVph7YsF8VSKyQ3BDFZwEVbok9yeDl2le/qo0S77WG2w== - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - integrity sha512-kT10v4dhrlLNcnO084hEjvXCI1wUG9qZLoz2RogxqDQQYy7IxjI/iMUkOtQTNEh6rzHxvdQWHsJyel1pKOVCxg== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.10.0, resolve@^1.22.1, resolve@^1.6.0, resolve@^1.8.1: +resolve@^1.10.0: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -3509,14 +3212,6 @@ resolve@^1.10.0, resolve@^1.22.1, resolve@^1.6.0, resolve@^1.8.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q== - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - rimraf@^2.6.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -3524,6 +3219,13 @@ rimraf@^2.6.2, rimraf@^2.6.3: dependencies: glob "^7.1.3" +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rimraf@~2.4.0: version "2.4.5" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" @@ -3531,32 +3233,6 @@ rimraf@~2.4.0: dependencies: glob "^6.0.1" -rimraf@~2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -run-async@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -run-parallel@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -rxjs@^5.5.2: - version "5.5.12" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" - integrity sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw== - dependencies: - symbol-observable "1.0.1" - safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -3582,9 +3258,9 @@ safe-regex-test@^1.0.0: is-regex "^1.1.4" safe-stable-stringify@^2.3.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz#ec7b037768098bf65310d1d64370de0dc02353aa" - integrity sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA== + version "2.4.3" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" @@ -3601,7 +3277,12 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: +secure-json-parse@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" + integrity sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw== + +"semver@2 || 3 || 4 || 5", semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -3621,6 +3302,11 @@ semver@^6.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@~7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -3660,23 +3346,6 @@ setprototypeof@1.2.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - -shimmer@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -3698,12 +3367,12 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== +simple-update-notifier@^1.0.7: + version "1.1.0" + resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz#67694c121de354af592b347cdba798463ed49c82" + integrity sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg== dependencies: - is-fullwidth-code-point "^2.0.0" + semver "~7.0.0" source-map@^0.6.1: version "0.6.1" @@ -3723,9 +3392,9 @@ spawn-wrap@^1.4.2: which "^1.3.0" spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" @@ -3744,9 +3413,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.12" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz#69077835abe2710b65f03969898b6637b505a779" - integrity sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA== + version "3.0.13" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== sprintf-js@~1.0.2: version "1.0.3" @@ -3768,52 +3437,29 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -stack-chain@^1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" - integrity sha512-D8cWtWVdIe/jBA7v5p5Hwl5yOSOrmZPWDPe2KxQ5UAGD+nxbxU0lKXA4h85Ta6+qgdKVL3vUxsbIZjc1kBG7ug== - stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== -standard-engine@~9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-9.0.0.tgz#d3a3d74c4c1b91f51a1e66362465261ca7610316" - integrity sha512-ZfNfCWZ2Xq67VNvKMPiVMKHnMdvxYzvZkf1AH8/cw2NLDBm5LRsxMqvEJpsjLI/dUosZ3Z1d6JlHDp5rAvvk2w== - dependencies: - deglob "^2.1.0" - get-stdin "^6.0.0" - minimist "^1.1.0" - pkg-conf "^2.0.0" - -standard@^12.0.1: - version "12.0.1" - resolved "https://registry.yarnpkg.com/standard/-/standard-12.0.1.tgz#0fc5a8aa6c34c546c5562aae644242b24dae2e61" - integrity sha512-UqdHjh87OG2gUrNCSM4QRLF5n9h3TFPwrCNyVlkqu31Hej0L/rc8hzKqVvkb2W3x0WMq7PzZdkLfEcBhVOR6lg== - dependencies: - eslint "~5.4.0" - eslint-config-standard "12.0.0" - eslint-config-standard-jsx "6.0.2" - eslint-plugin-import "~2.14.0" - eslint-plugin-node "~7.0.1" - eslint-plugin-promise "~4.0.0" - eslint-plugin-react "~7.11.1" - eslint-plugin-standard "~4.0.0" - standard-engine "~9.0.0" - statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +stop-iteration-iterator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== + dependencies: + internal-slot "^1.0.4" + streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -"string-width@^1.0.2 || 2", string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2": version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -3830,6 +3476,24 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trim@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + string.prototype.trimend@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" @@ -3883,12 +3547,19 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-json-comments@2.0.1, strip-json-comments@^2.0.1: +strip-json-comments@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== @@ -3921,7 +3592,7 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== -supports-color@^5.3.0: +supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -3941,34 +3612,17 @@ supports-preserve-symlinks-flag@^1.0.0: integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== swagger-ui-dist@>=4.11.0: - version "4.15.5" - resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-4.15.5.tgz#cda226a79db2a9192579cc1f37ec839398a62638" - integrity sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA== + version "4.18.1" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-4.18.1.tgz#da77cee1531af3f989b3da9dd8cddc5b9fa5715d" + integrity sha512-n7AT4wzKIPpHy/BGflJOepGMrbY/7Cd5yVd9ptVczaJGAKScbVJrZxFbAE2ZSZa8KmqdQ0+pOs3/5mWY5tSMZQ== swagger-ui-express@^4.1.3: - version "4.6.0" - resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-4.6.0.tgz#fc297d80c614c80f5d7def3dab50b56428cfe1c9" - integrity sha512-ZxpQFp1JR2RF8Ar++CyJzEDdvufa08ujNUJgMVTMWPi86CuQeVdBtvaeO/ysrz6dJAYXf9kbVNhWD7JWocwqsA== + version "4.6.2" + resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-4.6.2.tgz#61b2cb9fd7932cdccff99e0efdf700a5459e493c" + integrity sha512-MHIOaq9JrTTB3ygUJD+08PbjM5Tt/q7x80yz9VTFIatw8j5uIWKcr90S0h5NLMzFEDC6+eVprtoeA5MDZXCUKQ== dependencies: swagger-ui-dist ">=4.11.0" -symbol-observable@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" - integrity sha512-Kb3PrPYz4HanVF1LVGuAdW6LoVgIwjUYJGzFe7NDrBLCN4lsV/5J0MFurV+ygS4bRVwrCEt2c7MQ1R2a72oJDw== - -table@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" - integrity sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg== - dependencies: - ajv "^6.0.1" - ajv-keywords "^3.0.0" - chalk "^2.1.0" - lodash "^4.17.4" - slice-ansi "1.0.0" - string-width "^2.1.1" - tc-core-library-js@appirio-tech/tc-core-library-js.git#v2.6.4: version "2.4.1" resolved "https://codeload.github.com/appirio-tech/tc-core-library-js/tar.gz/df0b36c51cf80918194cbff777214b3c0cf5a151" @@ -3997,28 +3651,18 @@ text-hex@1.0.x: resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" @@ -4033,6 +3677,10 @@ topcoder-bus-api-wrapper@topcoder-platform/tc-bus-api-wrapper.git: superagent "^3.8.3" tc-core-library-js appirio-tech/tc-core-library-js.git#v2.6.4 +"topcoder-interface@github:topcoder-platform/plat-interface-definition#v0.0.46": + version "1.0.0" + resolved "https://codeload.github.com/topcoder-platform/plat-interface-definition/tar.gz/8ed5b7686125a17209c85c33f69c92476625e3c1" + topo@3.x.x: version "3.0.3" resolved "https://registry.yarnpkg.com/topo/-/topo-3.0.3.tgz#d5a67fb2e69307ebeeb08402ec2a2a6f5f7ad95c" @@ -4040,6 +3688,13 @@ topo@3.x.x: dependencies: hoek "6.x.x" +touch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" + integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== + dependencies: + nopt "~1.0.10" + tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -4053,10 +3708,10 @@ triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== -tslib@^2.3.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" - integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +tslib@^2.4.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== tunnel-agent@^0.6.0: version "0.6.0" @@ -4070,13 +3725,6 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== - dependencies: - prelude-ls "~1.1.2" - type-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -4109,10 +3757,10 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA== +undefsafe@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" + integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" @@ -4203,6 +3851,16 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" +which-collection@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" + integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== + dependencies: + is-map "^2.0.1" + is-set "^2.0.1" + is-weakmap "^2.0.1" + is-weakset "^2.0.1" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -4260,11 +3918,6 @@ winston@^3.8.2: triple-beam "^1.3.0" winston-transport "^4.5.0" -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -4274,6 +3927,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -4288,13 +3950,6 @@ write-file-atomic@^2.4.2: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - integrity sha512-CJ17OoULEKXpA5pef3qLj5AxTJ6mSt7g84he2WIskKwqFO4T97d5V7Tadl0DYDk7qyUOQD5WlUlOMChaYrhxeA== - dependencies: - mkdirp "^0.5.1" - xml2js@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" @@ -4316,16 +3971,16 @@ xss@^1.0.8: commander "^2.20.3" cssfilter "0.0.10" -xtend@^4.0.0, xtend@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^2.0.0, yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -4347,6 +4002,11 @@ yargs-parser@13.1.2, yargs-parser@^13.0.0, yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-unparser@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" @@ -4371,3 +4031,16 @@ yargs@13.3.2, yargs@^13.2.2, yargs@^13.3.0: which-module "^2.0.0" y18n "^4.0.0" yargs-parser "^13.1.2" + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2"