From 1fec74b9f2c0a785c756e62988f24242237dfeda Mon Sep 17 00:00:00 2001 From: David Adewole Date: Tue, 29 Jun 2021 15:50:21 +0100 Subject: [PATCH 01/22] lighthouse-runner --- accounts/.env | 4 +- backend/.env | 4 +- backend/backend/api/lighthouse.js | 330 ++ .../middlewares/lighthouseAuthorization.js | 137 + backend/backend/models/lighthouse.js | 21 + backend/backend/services/lighthouseService.js | 150 + backend/backend/services/monitorService.js | 85 + backend/server.js | 1 + dashboard/.env | 4 +- lighthouse-runner/.env | 4 + lighthouse-runner/index.js | 75 + lighthouse-runner/package-lock.json | 5194 +++++++++++++++++ lighthouse-runner/package.json | 31 + lighthouse-runner/utils/api.js | 109 + lighthouse-runner/utils/config.js | 46 + lighthouse-runner/utils/errorService.js | 32 + lighthouse-runner/utils/lighthouse.js | 59 + lighthouse-runner/utils/urlService.js | 33 + lighthouse-runner/workers/main.js | 23 + lighthouse-runner/workers/urlMonitors.js | 236 + 20 files changed, 6572 insertions(+), 6 deletions(-) create mode 100644 backend/backend/api/lighthouse.js create mode 100644 backend/backend/middlewares/lighthouseAuthorization.js create mode 100644 backend/backend/models/lighthouse.js create mode 100644 backend/backend/services/lighthouseService.js create mode 100644 lighthouse-runner/.env create mode 100644 lighthouse-runner/index.js create mode 100644 lighthouse-runner/package-lock.json create mode 100644 lighthouse-runner/package.json create mode 100755 lighthouse-runner/utils/api.js create mode 100644 lighthouse-runner/utils/config.js create mode 100755 lighthouse-runner/utils/errorService.js create mode 100644 lighthouse-runner/utils/lighthouse.js create mode 100755 lighthouse-runner/utils/urlService.js create mode 100644 lighthouse-runner/workers/main.js create mode 100755 lighthouse-runner/workers/urlMonitors.js diff --git a/accounts/.env b/accounts/.env index 4fe4557e50..039551cc8b 100644 --- a/accounts/.env +++ b/accounts/.env @@ -4,6 +4,6 @@ STRIPE_PUBLIC_KEY=pk_test_UynUDrFmbBmFVgJXd9EZCvBj00QAVpdwPv AMPLITUDE_PUBLIC_KEY=cb70632f45c1ca7fe6180812c0d6494a SKIP_PREFLIGHT_CHECK=true PUBLIC_URL=/accounts -#REACT_APP_IS_SAAS_SERVICE=true -#IS_SAAS_SERVICE=true +REACT_APP_IS_SAAS_SERVICE=true +IS_SAAS_SERVICE=true #REACT_APP_DISABLE_SIGNUP=true diff --git a/backend/.env b/backend/.env index c271bacb24..33552de80e 100755 --- a/backend/.env +++ b/backend/.env @@ -10,9 +10,9 @@ MONGO_URL=mongodb://localhost:27017/fyipedb REDIS_HOST=localhost CLUSTER_KEY=f414c23b4cdf4e84a6a66ecfd528eff2 TEST_TWILIO_NUMBER=+919910568840 -#IS_SAAS_SERVICE=true +IS_SAAS_SERVICE=true ENCRYPTION_KEY=01234567890123456789012345678901 -#IS_TESTING=true +IS_TESTING=true PUSHNOTIFICATION_PRIVATE_KEY=8aXTsH48-cegK-xBApLxxOezCOZIjaWpg81Dny2zbio PUSHNOTIFICATION_PUBLIC_KEY=BFAPbOTTU14VbTe_dnoYlVnOPLKUNm8GYmC50n3i4Ps64sk1Xqx8e894Clrscn1L2PsQ8-l4SsJVw7NRg4cx69Y PUSHNOTIFICATION_URL=mailto:support@fyipe.com diff --git a/backend/backend/api/lighthouse.js b/backend/backend/api/lighthouse.js new file mode 100644 index 0000000000..59d9e7e8ef --- /dev/null +++ b/backend/backend/api/lighthouse.js @@ -0,0 +1,330 @@ +/** + * + * Copyright HackerBay, Inc. + * + */ + +const express = require('express'); +const LighthouseService = require('../services/LighthouseService'); +const ProbeService = require('../services/ProbeService'); +const MonitorService = require('../services/monitorService'); +const ProjectService = require('../services/projectService'); +const LighthouseLogService = require('../services/lighthouseLogService'); +const router = express.Router(); +const isAuthorizedAdmin = require('../middlewares/clusterAuthorization') + .isAuthorizedAdmin; + +const sendErrorResponse = require('../middlewares/response').sendErrorResponse; +const sendItemResponse = require('../middlewares/response').sendItemResponse; +const sendListResponse = require('../middlewares/response').sendListResponse; +const getUser = require('../middlewares/user').getUser; +const { isAuthorized } = require('../middlewares/authorization'); +const storage = require('../middlewares/upload'); +const { isAuthorizedLighthouse } = require('../middlewares/lighthouseAuthorization'); + + +router.post('/', getUser, isAuthorizedAdmin, async function (req, res) { + try { + const data = req.body; + const lighthouse = await LighthouseService.create(data); + return sendItemResponse(req, res, lighthouse); + } catch (error) { + return sendErrorResponse(req, res, error); + } +}); + +router.get('/', getUser, isAuthorizedAdmin, async function (req, res) { + try { + const skip = req.query.skip || 0; + const limit = req.query.limit || 0; + const lighthouse = await LighthouseService.findBy({}, limit, skip); + const count = await LighthouseService.countBy({}); + return sendListResponse(req, res, lighthouse, count); + } catch (error) { + return sendErrorResponse(req, res, error); + } +}); + +router.put('/:id', getUser, isAuthorizedAdmin, async function (req, res) { + try { + const data = req.body; + const lighthouse = await LighthouseService.updateOneBy( + { _id: req.params.id }, + data + ); + return sendItemResponse(req, res, lighthouse); + } catch (error) { + return sendErrorResponse(req, res, error); + } +}); + +router.delete('/:id', getUser, isAuthorizedAdmin, async function (req, res) { + try { + const lighthouse = await LighthouseService.deleteBy({ _id: req.params.id }); + return sendItemResponse(req, res, lighthouse); + } catch (error) { + return sendErrorResponse(req, res, error); + } +}); + +// Route +// Description: Updating profile setting. +// Params: +// Param 1: req.headers-> {authorization}; req.user-> {id}; req.files-> {profilePic}; +// Returns: 200: Success, 400: Error; 500: Server Error. + +router.get('/monitors', isAuthorizedLighthouse, async function (req, res) { + try { + const monitors = await MonitorService.getUrlMonitors( + req.lighthouse.id, + new Date(new Date().getTime() - 60 * 1000) + ); + console.log("Get Lighthouse Monitors: ", monitors); + //Update the lastAlive in the lighthouse servers list located in the status pages. + if (monitors.length > 0) { + const projectIds = {}; + for (const monitor of monitors) { + const project = await ProjectService.findOneBy({ + _id: monitor.projectId, + }); + const projectId = project + ? project.parentProjectId + ? project.parentProjectId._id + : project._id + : monitor.projectId; + projectIds[projectId] = true; + } + for (const projectId of Object.keys(projectIds)) { + const lighthouse = await LighthouseService.findOneBy({ + _id: req.lighthouse.id, + }); + global.io.emit(`updatelighthouse-${projectId}`, lighthouse); + } + } + return sendListResponse( + req, + res, + JSON.stringify(monitors), + monitors.length + ); + } catch (error) { + return sendErrorResponse(req, res, error); + } +}); + +router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( + req, + response +) { + // let release; + try { + console.log("Pinging :", req.body); + console.log("Pinging 3 :", req.lighthouse); + const { + monitor, + res, + resp, + rawResp, + type, + retryCount, + } = req.body; + + let status, + log, + reason, + data = {}; + let matchedCriterion; + + if (type === 'url') { + const { + stat: validUp, + successReasons: upSuccessReasons, + failedReasons: upFailedReasons, + matchedCriterion: matchedUpCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.up + ? ProbeService.conditions( + monitor.type, + monitor.criteria.up, + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); + const { + stat: validDegraded, + successReasons: degradedSuccessReasons, + failedReasons: degradedFailedReasons, + matchedCriterion: matchedDegradedCriterion, + } = await (monitor && + monitor.criteria && + monitor.criteria.degraded + ? ProbeService.conditions( + monitor.type, + monitor.criteria.degraded, + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); + const { + stat: validDown, + successReasons: downSuccessReasons, + failedReasons: downFailedReasons, + matchedCriterion: matchedDownCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.down + ? ProbeService.conditions( + monitor.type, + [ + ...monitor.criteria.down.filter( + criterion => criterion.default !== true + ), + ], + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); + + if (validUp) { + status = 'online'; + reason = upSuccessReasons; + matchedCriterion = matchedUpCriterion; + } else if (validDegraded) { + status = 'degraded'; + reason = [...degradedSuccessReasons, ...upFailedReasons]; + matchedCriterion = matchedDegradedCriterion; + } else if (validDown) { + matchedCriterion = matchedDownCriterion; + status = 'offline'; + reason = [ + ...downSuccessReasons, + ...degradedFailedReasons, + ...upFailedReasons, + ]; + } else { + status = 'offline'; + reason = [ + ...downFailedReasons, + ...degradedFailedReasons, + ...upFailedReasons, + ]; + if (monitor.criteria.down) { + matchedCriterion = monitor.criteria.down.find( + criterion => criterion.default === true + ); + } + } + data.status = status; + data.reason = reason; + } + + data = req.body; + data.responseTime = res || 0; + data.responseStatus = resp && resp.status ? resp.status : null; + data.status = status; + data.sslCertificate = + resp && resp.sslCertificate ? resp.sslCertificate : null; + data.lighthouseScanStatus = + resp && resp.lighthouseScanStatus + ? resp.lighthouseScanStatus + : null; + data.performance = + resp && resp.performance ? resp.performance : null; + data.accessibility = + resp && resp.accessibility ? resp.accessibility : null; + data.bestPractices = + resp && resp.bestPractices ? resp.bestPractices : null; + data.seo = resp && resp.seo ? resp.seo : null; + data.pwa = resp && resp.pwa ? resp.pwa : null; + data.lighthouseData = + resp && resp.lighthouseData ? resp.lighthouseData : null; + data.retryCount = retryCount || 0; + data.reason = reason; + data.response = rawResp; + + + data.matchedCriterion = matchedCriterion; + console.log("Data before monitor update: ", data); + // update monitor to save the last matched criterion + await MonitorService.updateOneBy( + { + _id: monitor._id, + }, + { + lastMatchedCriterion: matchedCriterion, + } + ); + data.monitorId = req.params.monitorId || monitor._id; + data.lighthouseId = req.lighthouse && req.lighthouse.id ? req.lighthouse.id : null; + data.reason = + data && data.reason && data.reason.length + ? data.reason.filter( + (item, pos, self) => self.indexOf(item) === pos + ) + : data.reason; + const index = + data.reason && data.reason.indexOf('Request Timed out'); + if (index > -1) { + data.reason = + data && data.reason && data.reason.length + ? data.reason.filter( + item => !item.includes('Response Time is') + ) + : data.reason; + } + console.log("Data Lighthouse update: ", data); + if (data.lighthouseScanStatus) { + if (data.lighthouseScanStatus === 'scanning') { + await MonitorService.updateOneBy( + { _id: data.monitorId }, + { + lighthouseScanStatus: data.lighthouseScanStatus, + }, + { fetchLightHouse: true } + ); + await LighthouseLogService.updateAllLighthouseLogs( + data.monitor.projectId, + data.monitorId, + { scanning: true } + ); + } else { + await MonitorService.updateOneBy( + { _id: data.monitorId }, + { + lighthouseScannedAt: Date.now(), + lighthouseScanStatus: data.lighthouseScanStatus, // scanned || failed + lighthouseScannedBy: data.lighthouseId, + } + ); + } + } else { + if (data.lighthouseData) { + data.scanning = false; + log = await LighthouseService.saveLighthouseLog(data); + } else { + data.matchedUpCriterion = + monitor && monitor.criteria && monitor.criteria.up; + data.matchedDownCriterion = + monitor && monitor.criteria && monitor.criteria.down; + data.matchedDegradedCriterion = + monitor && + monitor.criteria && + monitor.criteria.degraded; + + log = await LighthouseService.saveMonitorLog(data); + } + } + console.log("Sent Log: ", log); + console.log("Sent Response: ", response); + console.log("Sent Response: ", req); + return sendItemResponse(req, response, log); + } catch (error) { + return sendErrorResponse(req, response, error); + } finally { + // if (release) { + // release(); + // } + } +}); + +module.exports = router; diff --git a/backend/backend/middlewares/lighthouseAuthorization.js b/backend/backend/middlewares/lighthouseAuthorization.js new file mode 100644 index 0000000000..a91be592dc --- /dev/null +++ b/backend/backend/middlewares/lighthouseAuthorization.js @@ -0,0 +1,137 @@ +/** + * + * Copyright HackerBay, Inc. + * + */ + const LighthouseService = require('../services/lighthouseService'); + const sendErrorResponse = require('../middlewares/response').sendErrorResponse; + const ErrorService = require('../services/errorService'); + const CLUSTER_KEY = process.env.CLUSTER_KEY; + module.exports = { + isAuthorizedLighthouse: async function (req, res, next) { + console.log("Sent Values: ",req.headers); + + try { + let lighthouseKey, lighthouseName, clusterKey, lighthouseVersion; + + if (req.params.lighthousekey) { + lighthouseKey = req.params.lighthousekey; + } else if (req.query.lighthouseKey) { + lighthouseKey = req.query.lighthousekey; + } else if (req.headers['lighthousekey']) { + lighthouseKey = req.headers['lighthousekey']; + } else if (req.headers['lighthousekey']) { + lighthouseKey = req.headers['lighthousekey']; + } else if (req.body.lighthouseKey) { + lighthouseKey = req.body.lighthouseKey; + } else { + return sendErrorResponse(req, res, { + code: 400, + message: 'lighthouse Key not found.', + }); + } + + if (req.params.lighthousename) { + lighthouseName = req.params.lighthousename; + } else if (req.query.lighthousename) { + lighthouseName = req.query.lighthousename; + } else if (req.headers['lighthousename']) { + lighthouseName = req.headers['lighthousename']; + } else if (req.headers['lighthousename']) { + lighthouseName = req.headers['lighthousename']; + } else if (req.body.lighthouseName) { + lighthouseName = req.body.lighthousename; + } else { + return sendErrorResponse(req, res, { + code: 400, + message: 'lighthouse Name not found.', + }); + } + + if (req.params.clusterKey) { + clusterKey = req.params.clusterkey; + } else if (req.query.clusterKey) { + clusterKey = req.query.clusterkey; + } else if (req.headers['clusterKey']) { + clusterKey = req.headers['clusterKey']; + } else if (req.headers['clusterkey']) { + clusterKey = req.headers['clusterkey']; + } else if (req.body.clusterKey) { + clusterKey = req.body.clusterKey; + } + + if (req.params.lighthouseversion) { + lighthouseVersion = req.params.lighthouseversion; + } else if (req.query.lighthouseversion) { + lighthouseVersion = req.query.lighthouseversion; + } else if (req.headers['lighthouseversion']) { + lighthouseVersion = req.headers['lighthouseversion']; + } else if (req.body.lighthouseversion) { + lighthouseVersion = req.body.lighthouseversion; + } + + console.log("Light House key: ", lighthouseKey); + let lighthouse = null; + + if (clusterKey && clusterKey === CLUSTER_KEY) { + // if cluster key matches then just query by lighthouse name, + // because if the lighthouse key does not match, we can update lighthouse key later + // without updating mongodb database manually. + lighthouse = await LighthouseService.findOneBy({ lighthouseName }); + } else { + lighthouse = await LighthouseService.findOneBy({ lighthouseKey, lighthouseName }); + } + + if (!lighthouse && (!clusterKey || clusterKey !== CLUSTER_KEY)) { + return sendErrorResponse(req, res, { + code: 400, + message: 'lighthouse key and lighthouse name do not match.', + }); + } + + if (!lighthouse) { + //create a new lighthouse. + lighthouse = await LighthouseService.create({ + lighthouseKey, + lighthouseName, + lighthouseVersion, + }); + } + + if (lighthouse.lighthouseKey !== lighthouseKey) { + //update lighthouse key becasue it does not match. + await LighthouseService.updateOneBy( + { + lighthouseName, + }, + { lighthouseKey } + ); + } + req.lighthouse = {}; + req.lighthouse.id = lighthouse._id; + console.log("Lighthouse ID: ", req.lighthouse); + //await LighthouseService.updateLighthouseStatus(lighthouse._id); + + //Update lighthouse version + const lighthouseValue = await LighthouseService.findOneBy({ + lighthouseKey, + lighthouseName, + }); + + if (!lighthouseValue.version || lighthouseValue.version !== lighthouseVersion) { + await LighthouseService.updateOneBy( + { + lighthouseName, + }, + { version: lighthouseVersion } + ); + } + + next(); + } catch (error) { + ErrorService.log('lighthouseAuthorization.isAuthorizedLighthouse', error); + throw error; + } + }, + }; + \ No newline at end of file diff --git a/backend/backend/models/lighthouse.js b/backend/backend/models/lighthouse.js new file mode 100644 index 0000000000..49c4caf524 --- /dev/null +++ b/backend/backend/models/lighthouse.js @@ -0,0 +1,21 @@ +/** + * + * Copyright HackerBay, Inc. + * + */ + + const mongoose = require('../config/db'); + + const Schema = mongoose.Schema; + const lighthouseSchema = new Schema({ + createdAt: { type: Date, default: Date.now }, + lighthouseKey: { type: String }, + lighthouseName: { type: String }, + version: { type: String }, + lastAlive: { type: Date, default: Date.now }, + deleted: { type: Boolean, default: false }, + deletedAt: { type: Date }, + }); + + module.exports = mongoose.model('lighthouse', lighthouseSchema); + \ No newline at end of file diff --git a/backend/backend/services/lighthouseService.js b/backend/backend/services/lighthouseService.js new file mode 100644 index 0000000000..7486fb3b27 --- /dev/null +++ b/backend/backend/services/lighthouseService.js @@ -0,0 +1,150 @@ +module.exports = { + create: async function(data) { + try { + const _this = this; + let lighthouseKey; + if (data.lighthouseKey) { + lighthouseKey = data.lighthouseKey; + } else { + lighthouseKey = uuidv1(); + } + const storedlighthouse = await _this.findOneBy({ + lighthouseName: data.lighthouseName, + }); + if (storedlighthouse && storedlighthouse.lighthouseName) { + const error = new Error('lighthouse name already exists.'); + error.code = 400; + ErrorService.log('lighthouse.create', error); + throw error; + } else { + const lighthouse = new LighthouseModel(); + lighthouse.lighthouseKey = lighthouseKey; + lighthouse.lighthouseName = data.lighthouseName; + lighthouse.version = data.lighthouseVersion; + const savedlighthouse = await lighthouse.save(); + return savedlighthouse; + } + } catch (error) { + ErrorService.log('lighthouseService.create', error); + throw error; + } + }, + + updateOneBy: async function(query, data) { + try { + if (!query) { + query = {}; + } + + query.deleted = false; + const lighthouse = await LighthouseModel.findOneAndUpdate( + query, + { $set: data }, + { + new: true, + } + ); + return lighthouse; + } catch (error) { + ErrorService.log('lighthouseService.updateOneBy', error); + throw error; + } + }, + + findOneBy: async function(query) { + try { + if (!query) { + query = {}; + } + + query.deleted = false; + const lighthouse = await LighthouseModel.findOne(query, { + deleted: false, + }).lean(); + return lighthouse; + } catch (error) { + ErrorService.log('lighthouseService.findOneBy', error); + throw error; + } + }, + + conditions: async (monitorType, con, payload, resp, response) => { + const status = resp + ? resp.status + ? resp.status + : resp.statusCode + ? resp.statusCode + : null + : null; + const body = resp && resp.body ? resp.body : null; + const queryParams = resp && resp.queryParams ? resp.queryParams : null; + const headers = resp && resp.headers ? resp.headers : null; + const sslCertificate = + resp && resp.sslCertificate ? resp.sslCertificate : null; + const successReasons = []; + const failedReasons = []; + + let eventOccurred = false; + let matchedCriterion; + + if (con && con.length) { + eventOccurred = await some(con, async condition => { + let stat = true; + if ( + condition && + condition.criteria && + condition.criteria.condition && + condition.criteria.condition === 'and' + ) { + stat = await checkAnd( + payload, + condition.criteria, + status, + body, + sslCertificate, + response, + successReasons, + failedReasons, + monitorType, + queryParams, + headers + ); + } else if ( + condition && + condition.criteria && + condition.criteria.condition && + condition.criteria.condition === 'or' + ) { + stat = await checkOr( + payload, + condition.criteria, + status, + body, + sslCertificate, + response, + successReasons, + failedReasons, + monitorType, + queryParams, + headers + ); + } + if (stat) { + matchedCriterion = condition; + return true; + } + + return false; + }); + } + + return { + stat: eventOccurred, + successReasons, + failedReasons, + matchedCriterion, + }; + }, +} +const LighthouseModel = require('../models/lighthouse'); +const { some } = require('p-iteration'); \ No newline at end of file diff --git a/backend/backend/services/monitorService.js b/backend/backend/services/monitorService.js index abed0b5fd3..81d86b6129 100755 --- a/backend/backend/services/monitorService.js +++ b/backend/backend/services/monitorService.js @@ -695,6 +695,91 @@ module.exports = { } }, + async getUrlMonitors(lighthouseId, date) { + try { + const newdate = new Date(); + const monitors = await MonitorModel.find({ + $and: [ + { + deleted: false, + disabled: false, + }, + { + $or: [ + { + $and: [ + { + type: { + $in: [ + 'url', + ], + }, + }, + { + $or: [ + { + pollTime: { + $elemMatch: { + lighthouseId, + date: { $lt: date }, + }, + }, + }, + { + //pollTime doesn't include the probeId yet. + pollTime: { + $not: { + $elemMatch: { + lighthouseId, + }, + }, + }, + }, + ], + }, + ], + }, + ], + }, + ], + }); + + if (monitors && monitors.length) { + for (const monitor of monitors) { + if ( + monitor.pollTime.length === 0 || + !monitor.pollTime.some( + pt => String(pt.lighthouseId) === String(lighthouseId) + ) + ) { + await MonitorModel.updateOne( + { _id: monitor._id }, + { $push: { pollTime: { lighthouseId, date: newdate } } } + ); + } else { + await MonitorModel.updateOne( + { + _id: monitor._id, + pollTime: { + $elemMatch: { + lighthouseId, + }, + }, + }, + { $set: { 'pollTime.$.date': newdate } } + ); + } + } + return monitors; + } else { + return []; + } + } catch (error) { + ErrorService.log('monitorService.getUrlMonitors', error); + throw error; + } + }, + async updateMonitorPingTime(id) { try { const newdate = new Date(); diff --git a/backend/server.js b/backend/server.js index 6841de16f0..c3f927f241 100755 --- a/backend/server.js +++ b/backend/server.js @@ -203,6 +203,7 @@ app.use( ); app.use(['/probe', '/api/probe'], require('./backend/api/probe')); app.use(['/application', '/api/application'], require('./backend/api/applicationScanner')); +app.use(['/lighthouse', '/api/lighthouse'], require('./backend/api/lighthouse')); app.use(['/version', '/api/version'], require('./backend/api/version')); app.use(['/tutorial', '/api/tutorial'], require('./backend/api/tutorial')); app.use(['/audit-logs', '/api/audit-logs'], require('./backend/api/auditLogs')); diff --git a/dashboard/.env b/dashboard/.env index c26c818803..4c910fefeb 100644 --- a/dashboard/.env +++ b/dashboard/.env @@ -4,8 +4,8 @@ STRIPE_PUBLIC_KEY=pk_test_UynUDrFmbBmFVgJXd9EZCvBj00QAVpdwPv AMPLITUDE_PUBLIC_KEY=4b76c47248f969446af69dfdbf687d90 SKIP_PREFLIGHT_CHECK=true PUBLIC_URL=/dashboard -#REACT_APP_IS_SAAS_SERVICE=true -#IS_SAAS_SERVICE=true +REACT_APP_IS_SAAS_SERVICE=true +IS_SAAS_SERVICE=true REACT_APP_VERSION=$npm_package_version REACT_APP_PUSHNOTIFICATION_PUBLIC_KEY=BFAPbOTTU14VbTe_dnoYlVnOPLKUNm8GYmC50n3i4Ps64sk1Xqx8e894Clrscn1L2PsQ8-l4SsJVw7NRg4cx69Y STATUSPAGE_DOMAIN=staging-statuspage.fyipe.com \ No newline at end of file diff --git a/lighthouse-runner/.env b/lighthouse-runner/.env new file mode 100644 index 0000000000..acfe4a67d0 --- /dev/null +++ b/lighthouse-runner/.env @@ -0,0 +1,4 @@ +CLUSTER_KEY=f414c23b4cdf4e84a6a66ecfd528eff2 +LIGHTHOUSE_NAME=US +LIGHTHOUSE_KEY=33b674ca-9fdd-11e9-a2a3-2a2ae2dbccez +SERVER_URL=http://localhost:3002 diff --git a/lighthouse-runner/index.js b/lighthouse-runner/index.js new file mode 100644 index 0000000000..98f4b66e05 --- /dev/null +++ b/lighthouse-runner/index.js @@ -0,0 +1,75 @@ +const { NODE_ENV } = process.env; + +if (!NODE_ENV || NODE_ENV === 'development') { + // Load env vars from /backend/.env + require('custom-env').env(); +} + +process.on('exit', () => { + /* eslint-disable no-console */ + console.log('Lighthouse Shutting Shutdown'); +}); + +process.on('unhandledRejection', err => { + /* eslint-disable no-console */ + console.error('Unhandled rejection in Lighthouse process occurred'); + /* eslint-disable no-console */ + console.error(err); +}); + +process.on('uncaughtException', err => { + /* eslint-disable no-console */ + console.error('Uncaught exception in Lighthouse process occurred'); + /* eslint-disable no-console */ + console.error(err); +}); + +const express = require('express'); +const app = express(); +const http = require('http').createServer(app); +const cors = require('cors'); +const Main = require('./workers/main'); +const cron = require('node-cron'); +const config = require('./utils/config'); + +const cronMinuteStartTime = Math.floor(Math.random() * 50); + +app.use(cors()); +app.set('port', process.env.PORT || 3001); + +http.listen(app.get('port'), function() { + // eslint-disable-next-line + console.log( + `Lighthouse with Lighthouse Name ${config.lighthouseName} and Lighthouse Key ${ + config.lighthouseKey + } Started on port ${app.get('port')}. Fyipe API URL: ${ + config.serverUrl + }` + ); +}); + +app.get('/', function(req, res) { + res.setHeader('Content-Type', 'application/json'); + res.send( + JSON.stringify({ + status: 200, + message: 'Service Status - OK', + serviceType: 'fyipe-lighthouse', + }) + ); +}); + +//App Version +app.get(['/lighthouse/version', '/version'], function(req, res) { + res.setHeader('Content-Type', 'application/json'); + res.send({ lighthouseVersion: process.env.npm_package_version }); +}); + +// This cron runs every other minute. +cron.schedule('*/2 * * * *', () => { + setTimeout(() => { + Main.runJob(); + }, cronMinuteStartTime * 1000); +}); + +module.exports = app; \ No newline at end of file diff --git a/lighthouse-runner/package-lock.json b/lighthouse-runner/package-lock.json new file mode 100644 index 0000000000..ff230e38fb --- /dev/null +++ b/lighthouse-runner/package-lock.json @@ -0,0 +1,5194 @@ +{ + "name": "lighthouse-runner", + "version": "3.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "axios": "^0.21.1", + "chrome-launcher": "^0.14.0", + "cors": "^2.8.5", + "custom-env": "^2.0.1", + "express": "^4.17.1", + "get-ssl-certificate": "^2.3.3", + "lighthouse": "^8.0.0", + "moment": "^2.29.1", + "node-cron": "^3.0.0", + "node-fetch": "^2.6.1", + "ping": "^0.4.1", + "winston": "^3.3.3", + "winston-slack-transport": "^2.0.0" + }, + "devDependencies": { + "nodemon": "^2.0.7" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@types/node": { + "version": "15.12.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.5.tgz", + "integrity": "sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dependencies": { + "string-width": "^3.0.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "node_modules/ansi-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansi-styles/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ansi-styles/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/axe-core": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.2.1.tgz", + "integrity": "sha512-evY7DN8qSIbsW2H/TWQ1bX3sXN1d4MNb5Vb4n7BzPuCwRHdkZ1H2eNLuSh73EoQqkGKUtju2G2HCcjCfhvZIAA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-launcher": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.14.0.tgz", + "integrity": "sha512-W//HpflaW6qBGrmuskup7g+XJZN6w03ko9QSIe5CtcTal2u0up5SeReK3Ll1Why4Ey8dPkv8XSodZyHPnGbVHQ==", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "dependencies": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/color-string": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", + "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "dependencies": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", + "engines": { + "node": "*" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/csp_evaluator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/csp_evaluator/-/csp_evaluator-1.0.1.tgz", + "integrity": "sha512-9L57/vkuwH1tJv9Sw9t13xKGKyRR7OKn/pizcLCHK/83WH+sqRav0JCFBmBLmpurQAcz5usU3efS1rabOPV/qA==" + }, + "node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, + "node_modules/cssstyle": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.1.tgz", + "integrity": "sha512-7DYm8qe+gPx/h77QlCyFmX80+fGaE/6A/Ekl0zaszYOubvySO2saYFdQ78P29D0UsULxFKCetDGNaNRUdSF+2A==", + "dependencies": { + "cssom": "0.3.x" + } + }, + "node_modules/custom-env": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/custom-env/-/custom-env-2.0.1.tgz", + "integrity": "sha512-gVv19DBDuTQ8MM/WPlf8025Aa46Aqmfrr/kDxyDfXWe5t7C3+OgBsuhrsXTKQ4hGo+z1OuuaOQnhgTWIpvrz+w==", + "dependencies": { + "dotenv": "*", + "dotenv-expand": "^5.0.0" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/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==" + }, + "node_modules/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==" + }, + "node_modules/fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "node_modules/fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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==" + }, + "node_modules/follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/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==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/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==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-ssl-certificate": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/get-ssl-certificate/-/get-ssl-certificate-2.3.3.tgz", + "integrity": "sha512-aKYXS1S5+2IYw4W5+lKC/M+lvaNYPe0PhnQ144NWARcBg35H3ZvyVZ6y0LNGtiAxggFBHeO7LaVGO4bgHK4g1Q==", + "license": "MIT" + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dependencies": { + "ini": "1.3.7" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-link-header": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-0.8.0.tgz", + "integrity": "sha1-oitBoMmx4tj6wb8baXxr1TLV9eQ=" + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "node_modules/image-ssim": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/image-ssim/-/image-ssim-0.2.0.tgz", + "integrity": "sha1-g7Qsei5uS4VQVHf+aRf128VkIOU=" + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" + }, + "node_modules/intl-messageformat": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-4.4.0.tgz", + "integrity": "sha512-z+Bj2rS3LZSYU4+sNitdHrwnBhr0wO80ZJSW8EzKDBowwUe3Q/UsvgCGjrwa+HPzoGCLEb9HAjfJgo4j2Sac8w==", + "dependencies": { + "intl-messageformat-parser": "^1.8.1" + } + }, + "node_modules/intl-messageformat-parser": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-1.8.1.tgz", + "integrity": "sha512-IMSCKVf0USrM/959vj3xac7s8f87sc+80Y/ipBzdKy4ifBv5Gsj2tZ41EAaURVg01QU71fYr77uA8Meh6kELbg==", + "deprecated": "We've written a new parser that's 6x faster and is backwards compatible. Please use @formatjs/icu-messageformat-parser" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/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==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dependencies": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/jpeg-js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz", + "integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==" + }, + "node_modules/js-library-detector": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/js-library-detector/-/js-library-detector-6.4.0.tgz", + "integrity": "sha512-NB2sYpmgqiTd7PNNhgp6bnEZmjvTUdAbzxABvYXWLpTL/t158T6mPnD8uYNd0FDP73YWyMrTYDvPxqdvCTbv2g==" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lighthouse": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/lighthouse/-/lighthouse-8.0.0.tgz", + "integrity": "sha512-jjniPn8qIjczsKKR/f91hBpMFsGgrBvwmH/KoQ/0qJlXpymsrRf06Y6Vb8xJXJ1aaR0HiGjeVgg4RlwT5pqXrg==", + "dependencies": { + "axe-core": "4.2.1", + "chrome-launcher": "^0.14.0", + "configstore": "^5.0.1", + "csp_evaluator": "^1.0.1", + "cssstyle": "1.2.1", + "enquirer": "^2.3.6", + "http-link-header": "^0.8.0", + "intl-messageformat": "^4.4.0", + "jpeg-js": "^0.4.1", + "js-library-detector": "^6.4.0", + "lighthouse-logger": "^1.2.0", + "lighthouse-stack-packs": "^1.5.0", + "lodash.clonedeep": "^4.5.0", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "lodash.set": "^4.3.2", + "lookup-closest-locale": "6.0.4", + "metaviewport-parser": "0.2.0", + "open": "^6.4.0", + "parse-cache-control": "1.0.1", + "ps-list": "^7.2.0", + "raven": "^2.2.1", + "robots-parser": "^2.0.1", + "semver": "^5.3.0", + "speedline-core": "^1.4.3", + "third-party-web": "^0.12.2", + "update-notifier": "^4.1.0", + "ws": "3.3.2", + "yargs": "^16.1.1", + "yargs-parser": "^20.2.4" + }, + "bin": { + "chrome-debug": "lighthouse-core/scripts/manual-chrome-launcher.js", + "lighthouse": "lighthouse-cli/index.js", + "smokehouse": "lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/lighthouse-logger": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz", + "integrity": "sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw==", + "dependencies": { + "debug": "^2.6.8", + "marky": "^1.2.0" + } + }, + "node_modules/lighthouse-stack-packs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lighthouse-stack-packs/-/lighthouse-stack-packs-1.5.0.tgz", + "integrity": "sha512-ntVOqFsrrTQYrNf+W+sNE9GjddW+ab5QN0WrrCikjMFsUvEQ28CvT0SXcHPZXFtcsb1lMSuVaNCmEuj7oXtYGQ==" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "node_modules/lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, + "node_modules/logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "dependencies": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/lookup-closest-locale": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/lookup-closest-locale/-/lookup-closest-locale-6.0.4.tgz", + "integrity": "sha512-bWoFbSGe6f1GvMGzj17LrwMX4FhDXDwZyH04ySVCPbtOJADcSRguZNKewoJ3Ful/MOxD/wRHvFPadk/kYZUbuQ==" + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/marky": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.2.tgz", + "integrity": "sha512-k1dB2HNeaNyORco8ulVEhctyEGkKHb2YWAhDsxeFlW2nROIirsctBYzKwwS3Vza+sKTS1zO4Z+n9/+9WbGLIxQ==" + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/metaviewport-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/metaviewport-parser/-/metaviewport-parser-0.2.0.tgz", + "integrity": "sha1-U1w84cz2IjpQJf3cahw2UF9+fbE=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "dependencies": { + "mime-db": "1.48.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.33", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz", + "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", + "dependencies": { + "moment": ">= 2.9.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-cron": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.0.tgz", + "integrity": "sha512-DDwIvvuCwrNiaU7HEivFDULcaQualDv7KoNlB/UU1wPW0n1tDEmBJKhEIE6DlF2FuoOHcNbLJ8ITL2Iv/3AWmA==", + "dependencies": { + "moment-timezone": "^0.5.31" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/nodemon": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", + "integrity": "sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.3", + "update-notifier": "^4.1.0" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/open/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/ping": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/ping/-/ping-0.4.1.tgz", + "integrity": "sha512-zYouogtyis0QpEZwWY1T26iuIOMJx+ajtjVMcPKIdWRq2Ie3Ftkbel8I25M5kCAQQMQhsez6ZbPiYjNe7aBjSQ==", + "dependencies": { + "q": "1.x", + "underscore": "^1.12.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "engines": { + "node": ">=4" + } + }, + "node_modules/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==" + }, + "node_modules/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==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ps-list": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ps-list/-/ps-list-7.2.0.tgz", + "integrity": "sha512-v4Bl6I3f2kJfr5o80ShABNHAokIgY+wFDTQfE+X3zWYgSGQOCBeYptLZUpoOALBqO5EawmDN/tjTldJesd0ujQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raven": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/raven/-/raven-2.6.4.tgz", + "integrity": "sha512-6PQdfC4+DQSFncowthLf+B6Hr0JpPsFBgTVYTAOq7tCmx/kR4SXbeawtPch20+3QfUcQDoJBLjWW1ybvZ4kXTw==", + "dependencies": { + "cookie": "0.3.1", + "md5": "^2.2.1", + "stack-trace": "0.0.10", + "timed-out": "4.0.1", + "uuid": "3.3.2" + }, + "bin": { + "raven": "bin/raven" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/raven/node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raven/node_modules/uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/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==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "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" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/robots-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/robots-parser/-/robots-parser-2.3.0.tgz", + "integrity": "sha512-RvuCITckrHM9k8DxCCU9rqWpuuKRfVX9iHG751dC3/EdERxp9gJATxYYdYOT3L0T+TAT4+27lENisk/VbHm47A==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/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==" + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/speedline-core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/speedline-core/-/speedline-core-1.4.3.tgz", + "integrity": "sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog==", + "dependencies": { + "@types/node": "*", + "image-ssim": "^0.2.0", + "jpeg-js": "^0.4.1" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dependencies": { + "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" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/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==" + }, + "node_modules/third-party-web": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.12.3.tgz", + "integrity": "sha512-wnPlVUKzet4hnejKMEsVj5eIL0V2PLzgjJ3fLyGo9GV1pUOMa0NjeIzJNJ0pTEUL2GJAqlFKxo8EYML27SF/ng==" + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/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==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "node_modules/undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "dependencies": { + "debug": "^2.2.0" + } + }, + "node_modules/underscore": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dependencies": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "dependencies": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-slack-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/winston-slack-transport/-/winston-slack-transport-2.0.0.tgz", + "integrity": "sha1-hWk8hb5P6Uc9SKvWGWrLfljgZaU=", + "dependencies": { + "request": "^2.67.0" + }, + "engines": { + "node": ">= 0.6.0" + }, + "peerDependencies": { + "winston": ">=0.7.2" + } + }, + "node_modules/winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "dependencies": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport/node_modules/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==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/winston-transport/node_modules/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==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.2.tgz", + "integrity": "sha512-t+WGpsNxhMR4v6EClXS8r8km5ZljKJzyGhJf7goJz9k5Ye3+b5Bvno5rjqPuIBn5mnn5GBb7o8IrIWHxX1qOLQ==", + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + } + }, + "dependencies": { + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/node": { + "version": "15.12.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.5.tgz", + "integrity": "sha512-se3yX7UHv5Bscf8f1ERKvQOD6sTyycH3hdaoozvaLxgUiY5lIGEeH37AD0G0Qi9kPqihPn0HOfd2yaIEN9VwEg==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "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" + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "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==", + "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==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + }, + "dependencies": { + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "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": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "axe-core": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.2.1.tgz", + "integrity": "sha512-evY7DN8qSIbsW2H/TWQ1bX3sXN1d4MNb5Vb4n7BzPuCwRHdkZ1H2eNLuSh73EoQqkGKUtju2G2HCcjCfhvZIAA==" + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.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" + } + }, + "chrome-launcher": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.14.0.tgz", + "integrity": "sha512-W//HpflaW6qBGrmuskup7g+XJZN6w03ko9QSIe5CtcTal2u0up5SeReK3Ll1Why4Ey8dPkv8XSodZyHPnGbVHQ==", + "requires": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, + "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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", + "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "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" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "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==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "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" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" + }, + "csp_evaluator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/csp_evaluator/-/csp_evaluator-1.0.1.tgz", + "integrity": "sha512-9L57/vkuwH1tJv9Sw9t13xKGKyRR7OKn/pizcLCHK/83WH+sqRav0JCFBmBLmpurQAcz5usU3efS1rabOPV/qA==" + }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, + "cssstyle": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.1.tgz", + "integrity": "sha512-7DYm8qe+gPx/h77QlCyFmX80+fGaE/6A/Ekl0zaszYOubvySO2saYFdQ78P29D0UsULxFKCetDGNaNRUdSF+2A==", + "requires": { + "cssom": "0.3.x" + } + }, + "custom-env": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/custom-env/-/custom-env-2.0.1.tgz", + "integrity": "sha512-gVv19DBDuTQ8MM/WPlf8025Aa46Aqmfrr/kDxyDfXWe5t7C3+OgBsuhrsXTKQ4hGo+z1OuuaOQnhgTWIpvrz+w==", + "requires": { + "dotenv": "*", + "dotenv-expand": "^5.0.0" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "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" + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "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": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "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-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "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.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "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" + } + }, + "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": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": 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==" + }, + "get-ssl-certificate": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/get-ssl-certificate/-/get-ssl-certificate-2.3.3.tgz", + "integrity": "sha512-aKYXS1S5+2IYw4W5+lKC/M+lvaNYPe0PhnQ144NWARcBg35H3ZvyVZ6y0LNGtiAxggFBHeO7LaVGO4bgHK4g1Q==" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "requires": { + "ini": "1.3.7" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "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-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==" + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-link-header": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-0.8.0.tgz", + "integrity": "sha1-oitBoMmx4tj6wb8baXxr1TLV9eQ=" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.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" + } + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "image-ssim": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/image-ssim/-/image-ssim-0.2.0.tgz", + "integrity": "sha1-g7Qsei5uS4VQVHf+aRf128VkIOU=" + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==" + }, + "intl-messageformat": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-4.4.0.tgz", + "integrity": "sha512-z+Bj2rS3LZSYU4+sNitdHrwnBhr0wO80ZJSW8EzKDBowwUe3Q/UsvgCGjrwa+HPzoGCLEb9HAjfJgo4j2Sac8w==", + "requires": { + "intl-messageformat-parser": "^1.8.1" + } + }, + "intl-messageformat-parser": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-1.8.1.tgz", + "integrity": "sha512-IMSCKVf0USrM/959vj3xac7s8f87sc+80Y/ipBzdKy4ifBv5Gsj2tZ41EAaURVg01QU71fYr77uA8Meh6kELbg==" + }, + "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-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jpeg-js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz", + "integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==" + }, + "js-library-detector": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/js-library-detector/-/js-library-detector-6.4.0.tgz", + "integrity": "sha512-NB2sYpmgqiTd7PNNhgp6bnEZmjvTUdAbzxABvYXWLpTL/t158T6mPnD8uYNd0FDP73YWyMrTYDvPxqdvCTbv2g==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "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-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "requires": { + "package-json": "^6.3.0" + } + }, + "lighthouse": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/lighthouse/-/lighthouse-8.0.0.tgz", + "integrity": "sha512-jjniPn8qIjczsKKR/f91hBpMFsGgrBvwmH/KoQ/0qJlXpymsrRf06Y6Vb8xJXJ1aaR0HiGjeVgg4RlwT5pqXrg==", + "requires": { + "axe-core": "4.2.1", + "chrome-launcher": "^0.14.0", + "configstore": "^5.0.1", + "csp_evaluator": "^1.0.1", + "cssstyle": "1.2.1", + "enquirer": "^2.3.6", + "http-link-header": "^0.8.0", + "intl-messageformat": "^4.4.0", + "jpeg-js": "^0.4.1", + "js-library-detector": "^6.4.0", + "lighthouse-logger": "^1.2.0", + "lighthouse-stack-packs": "^1.5.0", + "lodash.clonedeep": "^4.5.0", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "lodash.set": "^4.3.2", + "lookup-closest-locale": "6.0.4", + "metaviewport-parser": "0.2.0", + "open": "^6.4.0", + "parse-cache-control": "1.0.1", + "ps-list": "^7.2.0", + "raven": "^2.2.1", + "robots-parser": "^2.0.1", + "semver": "^5.3.0", + "speedline-core": "^1.4.3", + "third-party-web": "^0.12.2", + "update-notifier": "^4.1.0", + "ws": "3.3.2", + "yargs": "^16.1.1", + "yargs-parser": "^20.2.4" + } + }, + "lighthouse-logger": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz", + "integrity": "sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw==", + "requires": { + "debug": "^2.6.8", + "marky": "^1.2.0" + } + }, + "lighthouse-stack-packs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lighthouse-stack-packs/-/lighthouse-stack-packs-1.5.0.tgz", + "integrity": "sha512-ntVOqFsrrTQYrNf+W+sNE9GjddW+ab5QN0WrrCikjMFsUvEQ28CvT0SXcHPZXFtcsb1lMSuVaNCmEuj7oXtYGQ==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, + "logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.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==" + } + } + }, + "lookup-closest-locale": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/lookup-closest-locale/-/lookup-closest-locale-6.0.4.tgz", + "integrity": "sha512-bWoFbSGe6f1GvMGzj17LrwMX4FhDXDwZyH04ySVCPbtOJADcSRguZNKewoJ3Ful/MOxD/wRHvFPadk/kYZUbuQ==" + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "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==" + } + } + }, + "marky": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.2.tgz", + "integrity": "sha512-k1dB2HNeaNyORco8ulVEhctyEGkKHb2YWAhDsxeFlW2nROIirsctBYzKwwS3Vza+sKTS1zO4Z+n9/+9WbGLIxQ==" + }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "metaviewport-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/metaviewport-parser/-/metaviewport-parser-0.2.0.tgz", + "integrity": "sha1-U1w84cz2IjpQJf3cahw2UF9+fbE=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "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.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" + }, + "mime-types": { + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "requires": { + "mime-db": "1.48.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "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" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "moment-timezone": { + "version": "0.5.33", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz", + "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", + "requires": { + "moment": ">= 2.9.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "node-cron": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.0.tgz", + "integrity": "sha512-DDwIvvuCwrNiaU7HEivFDULcaQualDv7KoNlB/UU1wPW0n1tDEmBJKhEIE6DlF2FuoOHcNbLJ8ITL2Iv/3AWmA==", + "requires": { + "moment-timezone": "^0.5.31" + } + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "nodemon": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", + "integrity": "sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==", + "dev": true, + "requires": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.3", + "update-notifier": "^4.1.0" + }, + "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 + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" + }, + "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": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "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" + } + }, + "open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "requires": { + "is-wsl": "^1.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + } + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "ping": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/ping/-/ping-0.4.1.tgz", + "integrity": "sha512-zYouogtyis0QpEZwWY1T26iuIOMJx+ajtjVMcPKIdWRq2Ie3Ftkbel8I25M5kCAQQMQhsez6ZbPiYjNe7aBjSQ==", + "requires": { + "q": "1.x", + "underscore": "^1.12.0" + } + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + }, + "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==" + }, + "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" + } + }, + "ps-list": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ps-list/-/ps-list-7.2.0.tgz", + "integrity": "sha512-v4Bl6I3f2kJfr5o80ShABNHAokIgY+wFDTQfE+X3zWYgSGQOCBeYptLZUpoOALBqO5EawmDN/tjTldJesd0ujQ==" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "requires": { + "escape-goat": "^2.0.0" + } + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "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==" + }, + "raven": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/raven/-/raven-2.6.4.tgz", + "integrity": "sha512-6PQdfC4+DQSFncowthLf+B6Hr0JpPsFBgTVYTAOq7tCmx/kR4SXbeawtPch20+3QfUcQDoJBLjWW1ybvZ4kXTw==", + "requires": { + "cookie": "0.3.1", + "md5": "^2.2.1", + "stack-trace": "0.0.10", + "timed-out": "4.0.1", + "uuid": "3.3.2" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "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" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "requires": { + "rc": "^1.2.8" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "robots-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/robots-parser/-/robots-parser-2.3.0.tgz", + "integrity": "sha512-RvuCITckrHM9k8DxCCU9rqWpuuKRfVX9iHG751dC3/EdERxp9gJATxYYdYOT3L0T+TAT4+27lENisk/VbHm47A==" + }, + "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==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "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==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + } + }, + "speedline-core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/speedline-core/-/speedline-core-1.4.3.tgz", + "integrity": "sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog==", + "requires": { + "@types/node": "*", + "image-ssim": "^0.2.0", + "jpeg-js": "^0.4.1" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "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": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "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==" + } + } + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "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" + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==" + }, + "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==" + }, + "third-party-web": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.12.3.tgz", + "integrity": "sha512-wnPlVUKzet4hnejKMEsVj5eIL0V2PLzgjJ3fLyGo9GV1pUOMa0NjeIzJNJ0pTEUL2GJAqlFKxo8EYML27SF/ng==" + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "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" + } + }, + "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": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + }, + "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" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "requires": { + "debug": "^2.2.0" + } + }, + "underscore": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + } + }, + "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" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "requires": { + "string-width": "^4.0.0" + } + }, + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + } + }, + "winston-slack-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/winston-slack-transport/-/winston-slack-transport-2.0.0.tgz", + "integrity": "sha1-hWk8hb5P6Uc9SKvWGWrLfljgZaU=", + "requires": { + "request": "^2.67.0" + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "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" + } + }, + "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" + } + } + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.2.tgz", + "integrity": "sha512-t+WGpsNxhMR4v6EClXS8r8km5ZljKJzyGhJf7goJz9k5Ye3+b5Bvno5rjqPuIBn5mnn5GBb7o8IrIWHxX1qOLQ==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" + } + } +} diff --git a/lighthouse-runner/package.json b/lighthouse-runner/package.json new file mode 100644 index 0000000000..5fbede9c2d --- /dev/null +++ b/lighthouse-runner/package.json @@ -0,0 +1,31 @@ +{ + "name": "lighthouse-runner", + "version": "3.0.0", + "description": "Lighthouse Runner for Url Monitor", + "main": "index.js", + "scripts": { + "start": "node --max-http-header-size=80000 index.js", + "dev": "nodemon --inspect=0.0.0.0 --max-http-header-size=80000 index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "David Adewole", + "license": "MIT", + "dependencies": { + "axios": "^0.21.1", + "chrome-launcher": "^0.14.0", + "cors": "^2.8.5", + "custom-env": "^2.0.1", + "express": "^4.17.1", + "get-ssl-certificate": "^2.3.3", + "lighthouse": "^8.0.0", + "moment": "^2.29.1", + "node-cron": "^3.0.0", + "node-fetch": "^2.6.1", + "ping": "^0.4.1", + "winston": "^3.3.3", + "winston-slack-transport": "^2.0.0" + }, + "devDependencies": { + "nodemon": "^2.0.7" + } +} diff --git a/lighthouse-runner/utils/api.js b/lighthouse-runner/utils/api.js new file mode 100755 index 0000000000..4dccbbd988 --- /dev/null +++ b/lighthouse-runner/utils/api.js @@ -0,0 +1,109 @@ +const axios = require('axios'); +const config = require('./config'); + +const _this = { + getHeaders: () => { + return { + 'Access-Control-Allow-Origin': '*', + Accept: 'application/json', + 'Content-Type': 'application/json;charset=UTF-8', + lighthouseName: config.lighthouseName, + lighthouseKey: config.lighthouseKey, + clusterKey: config.clusterKey, + lighthouseVersion: config.lighthouseVersion, + }; + }, + postApi: (url, data) => { + const headers = _this.getHeaders(); + + return new Promise((resolve, reject) => { + axios({ + method: 'POST', + url: `${config.serverUrl}/${url}`, + headers, + data, + }) + .then(function(response) { + resolve(response.data); + }) + .catch(function(error) { + if (error && error.response && error.response.data) + error = error.response.data; + if (error && error.data) { + error = error.data; + } + reject(error); + }); + }); + }, + + getApi: url => { + const headers = _this.getHeaders(); + return new Promise((resolve, reject) => { + axios({ + method: 'GET', + url: `${config.serverUrl}/${url}`, + headers, + }) + .then(function(response) { + resolve(response.data); + }) + .catch(function(error) { + if (error && error.response && error.response.data) + error = error.response.data; + if (error && error.data) { + error = error.data; + } + reject(error); + }); + }); + }, + + putApi: (url, data) => { + const headers = _this.getHeaders(); + return new Promise((resolve, reject) => { + axios({ + method: 'PUT', + url: `${config.serverUrl}/${url}`, + headers, + data, + }) + .then(function(response) { + resolve(response.data); + }) + .catch(function(error) { + if (error && error.response && error.response.data) + error = error.response.data; + if (error && error.data) { + error = error.data; + } + reject(error); + }); + }); + }, + + deleteApi: (url, data) => { + const headers = _this.getHeaders(); + return new Promise((resolve, reject) => { + axios({ + method: 'DELETE', + url: `${config.serverUrl}/${url}`, + headers, + data, + }) + .then(function(response) { + resolve(response.data); + }) + .catch(function(error) { + if (error && error.response && error.response.data) + error = error.response.data; + if (error && error.data) { + error = error.data; + } + reject(error); + }); + }); + }, +}; + +module.exports = _this; diff --git a/lighthouse-runner/utils/config.js b/lighthouse-runner/utils/config.js new file mode 100644 index 0000000000..eff9a6940e --- /dev/null +++ b/lighthouse-runner/utils/config.js @@ -0,0 +1,46 @@ +const packageJson = require('../package.json'); + +const COMMAND = { + linux: { + load: "top -b -n 2 | egrep --color 'load average|%Cpu'", + cpu: "egrep --color 'processor|cores' /proc/cpuinfo", + mem: "egrep --color 'Mem|Swap' /proc/meminfo", + disk: "df -h | egrep --color '/dev/xvda1|/dev/sda7|/dev/nvme0n1p1'", + temp: "sensors | egrep --color 'CPU'", + }, + darwin: { + load: "top -l 1 | egrep --color 'Load Avg|CPU usage'", + cpu: 'sysctl -n machdep.cpu.core_count', + mem: { + used: "top -l 1 | egrep --color 'PhysMem'", + total: 'sysctl -n hw.memsize', + swap: 'sysctl -n vm.swapusage', + }, + disk: "df -h | egrep --color '/dev/disk1s2'", + temp: 'sysctl -n machdep.xcpm.cpu_thermal_level', + }, + win: { + load: 'wmic cpu get loadpercentage', + cpu: 'wmic cpu get numberofcores', + mem: { + free: 'wmic os get freephysicalmemory', + total: 'wmic computersystem get totalphysicalmemory', + totalSwap: 'wmic os get totalvirtualmemorySize', + freeSwap: 'wmic os get freevirtualmemory', + }, + disk: { + total: 'wmic logicaldisk get size', + free: 'wmic logicaldisk get freespace', + }, + temp: 'wmic computersystem get thermalstate', + }, +}; + +module.exports = { + COMMAND, + serverUrl: process.env['SERVER_URL'], + lighthouseName: process.env['LIGHTHOUSE_NAME'], + lighthouseKey: process.env['LIGHTHOUSE_KEY'], + clusterKey: process.env['CLUSTER_KEY'], + lighthouseVersion: packageJson.version, +}; diff --git a/lighthouse-runner/utils/errorService.js b/lighthouse-runner/utils/errorService.js new file mode 100755 index 0000000000..2504fa322a --- /dev/null +++ b/lighthouse-runner/utils/errorService.js @@ -0,0 +1,32 @@ +const winston = require('winston'); +const Slack = require('winston-slack-transport'); + +if ( + process.env.PORT && + process.env.SLACK_ERROR_LOG_WEBHOOK && + process.env.SLACK_ERROR_LOG_CHANNEL +) { + winston.add(Slack, { + webhook_url: process.env.SLACK_ERROR_LOG_WEBHOOK, + channel: '#' + process.env.SLACK_ERROR_LOG_CHANNEL, + username: 'Error Bot', + handleExceptions: true, + }); +} + +module.exports = { + log: (functionName, error) => { + error = error && error.message ? error.message : error; + winston.error( + JSON.stringify( + { + error: String(error), + functionName: String(functionName), + stack: new Error().stack, + }, + 0, + 2 + ) + ); + }, +}; diff --git a/lighthouse-runner/utils/lighthouse.js b/lighthouse-runner/utils/lighthouse.js new file mode 100644 index 0000000000..dccf01a24e --- /dev/null +++ b/lighthouse-runner/utils/lighthouse.js @@ -0,0 +1,59 @@ +const lighthouse = require('lighthouse'); +const chromeLauncher = require('chrome-launcher'); +const ErrorService = require('./errorService'); + +function launchChromeAndRunLighthouse( + url, + options = { chromeFlags: ['--headless', '--disable-gpu', '--no-sandbox'] }, + config = null +) { + return chromeLauncher.launch(options).then(chrome => { + options.port = chrome.port; + return lighthouse(url, options, config).then(results => { + return chrome.kill().then(() => results.lhr); + }); + }); +} + +process.on('message', url => { + launchChromeAndRunLighthouse(url) + .then(results => { + const issues = {}; + const categories = results.categories; + const audits = results.audits; + for (const category in categories) { + const ids = categories[category].auditRefs.map( + auditRef => auditRef.id + ); + issues[category] = ids + .map(id => + audits[id] && + audits[id].score !== null && + audits[id].score < 1 + ? audits[id] + : id + ) + .filter(id => typeof id !== 'string'); + } + + const result = { + lighthouseData: { url, issues }, + performance: Math.ceil( + results.categories.performance.score * 100 + ), + accessibility: Math.ceil( + results.categories.accessibility.score * 100 + ), + bestPractices: Math.ceil( + results.categories['best-practices'].score * 100 + ), + seo: Math.ceil(results.categories.seo.score * 100), + pwa: Math.ceil(results.categories.pwa.score * 100), + }; + process.send(result); + }) + .catch(error => { + process.send({ data: { url }, error }); + ErrorService.log('launchChromeAndRunLighthouse', error); + }); +}); diff --git a/lighthouse-runner/utils/urlService.js b/lighthouse-runner/utils/urlService.js new file mode 100755 index 0000000000..cd33f0ff1d --- /dev/null +++ b/lighthouse-runner/utils/urlService.js @@ -0,0 +1,33 @@ +const postApi = require('./api').postApi; + +module.exports = { + headers: async (val, type) => { + const header = {}; + if (type && type.length) { + header['Content-Type'] = type; + } + if (val && val.length) { + val.forEach(head => { + header[head.key] = head.value; + }); + } + return header; + }, + + body: async (val, type) => { + let bodyContent = {}; + if (type && type === 'formData' && val && val[0] && val[0].key) { + val.forEach(bod => { + bodyContent[bod.key] = bod.value; + }); + bodyContent = JSON.stringify(bodyContent); + } else if (type && type === 'text' && val && val.length) { + bodyContent = val; + } + return bodyContent; + }, + + ping: async function(monitorId, data) { + return await postApi(`lighthouse/ping/${monitorId}`, data); + }, +}; diff --git a/lighthouse-runner/workers/main.js b/lighthouse-runner/workers/main.js new file mode 100644 index 0000000000..f1fa65230f --- /dev/null +++ b/lighthouse-runner/workers/main.js @@ -0,0 +1,23 @@ +const getApi = require('../utils/api').getApi; +const UrlMonitors = require('./urlMonitors'); +const ErrorService = require('../utils/errorService'); + +module.exports = { + runJob: async function() { + try { + let monitors = await getApi('lighthouse/monitors'); + monitors = JSON.parse(monitors.data); // parse the stringified data + console.log("The Data Monitor: ", monitors);console.log("The Data Monitor: ", monitors); + await Promise.all( + monitors.map(monitor => { + if(monitor.type === 'url'){ + return UrlMonitors.ping(monitor); + } + return null; + }) + ); + } catch (error) { + ErrorService.log('getApi', error); + } + }, +} \ No newline at end of file diff --git a/lighthouse-runner/workers/urlMonitors.js b/lighthouse-runner/workers/urlMonitors.js new file mode 100755 index 0000000000..b77fefd055 --- /dev/null +++ b/lighthouse-runner/workers/urlMonitors.js @@ -0,0 +1,236 @@ +/* eslint-disable no-console */ +const UrlService = require('../utils/urlService'); +const ErrorService = require('../utils/errorService'); +const fetch = require('node-fetch'); +const sslCert = require('get-ssl-certificate'); +const { fork } = require('child_process'); +const moment = require('moment'); +const https = require('https'); +const http = require('http'); +const httpsAgent = new https.Agent({ + rejectUnauthorized: false, +}); +const httpAgent = new http.Agent(); + +// it collects all monitors then ping them one by one to store their response +// checks if the website of the url in the monitors is up or down +// creates incident if a website is down and resolves it when they come back up + +module.exports = { + ping: async monitor => { + console.log("Received Monitor to Ping: ",monitor); + try { + if (monitor && monitor.type) { + if (monitor.data.url) { + let retry = true; + let retryCount = 0; + while (retry) { + const { res, resp, rawResp } = await pingfetch( + monitor.data.url + ); + console.log("Res", res); + console.log("Resp", resp); + console.log("Raw Res", rawResp); + const response = await UrlService.ping(monitor._id, { + monitor, + res, + resp, + rawResp, + type: monitor.type, + retryCount, + }); + + if (response && !response.retry) { + retry = false; + } else { + retryCount++; + } + } + + const now = new Date().getTime(); + const scanIntervalInDays = monitor.lighthouseScannedAt + ? moment(now).diff( + moment(monitor.lighthouseScannedAt), + 'days' + ) + : -1; + if ( + (monitor.lighthouseScanStatus && + monitor.lighthouseScanStatus === 'scan') || + (monitor.lighthouseScanStatus && + monitor.lighthouseScanStatus === 'failed') || + ((!monitor.lighthouseScannedAt || + scanIntervalInDays > 0) && + (!monitor.lighthouseScanStatus || + monitor.lighthouseScanStatus !== 'scanning')) + ) { + await UrlService.ping(monitor._id, { + monitor, + resp: { lighthouseScanStatus: 'scanning' }, + }); + + const sites = monitor.siteUrls; + let failedCount = 0; + for (const url of sites) { + try { + const resp = await lighthouseFetch( + monitor, + url + ); + + await UrlService.ping(monitor._id, { + monitor, + resp, + }); + } catch (error) { + failedCount++; + ErrorService.log( + 'lighthouseFetch', + error.error + ); + } + } + + await UrlService.ping(monitor._id, { + monitor, + resp: { + lighthouseScanStatus: + failedCount === sites.length + ? 'failed' + : 'scanned', + }, + }); + } + } + } + } catch (error) { + ErrorService.log('UrlMonitors.ping', error); + throw error; + } + }, +}; + +const pingfetch = async url => { + const now = new Date().getTime(); + let resp, res, response; + + try { + let sslCertificate, data; + const urlObject = new URL(url); + const headers = { + 'User-Agent': + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36', + }; + try { + /* Try with a normal http / https agent. + If this fails we'll try with an agent which has + { + rejectUnauthorized: false, + } + + to check for self-signed SSL certs. + */ + + response = await fetch(url, { timeout: 500000, headers }); + res = new Date().getTime() - now; + data = await response.text(); + if (urlObject.protocol === 'https:') { + const certificate = await sslCert.get(urlObject.hostname); + if (certificate) { + sslCertificate = { + issuer: certificate.issuer, + expires: certificate.valid_to, + fingerprint: certificate.fingerprint, + selfSigned: false, + }; + } + } + } catch (e) { + /* Retry with an agent which has + + { + rejectUnauthorized: false, + } + + to check for self-signed SSL certs. + */ + + response = await fetch(url, { + timeout: 500000, + ...(url.startsWith('https') + ? { agent: httpsAgent } + : { agent: httpAgent }), + headers, + }); + res = new Date().getTime() - now; + data = await response.text(); + if (urlObject.protocol === 'https:') { + const certificate = await sslCert.get(urlObject.hostname); + if (certificate) { + sslCertificate = { + issuer: certificate.issuer, + expires: certificate.valid_to, + fingerprint: certificate.fingerprint, + selfSigned: e.code === 'DEPTH_ZERO_SELF_SIGNED_CERT', + }; + } + } + } + + resp = { status: response.status, body: data, sslCertificate }; + } catch (error) { + res = new Date().getTime() - now; + resp = { status: 408, body: error }; + } + + // this hard coded value will be removed soon + res = res / 100; + + return { + res, + resp, + rawResp: { + ok: response && response.ok ? response.ok : null, + status: + response && response.status + ? response.status + : resp && resp.status + ? resp.status + : null, + statusText: + response && response.statusText ? response.statusText : null, + headers: + response && response.headers && response.headers.raw() + ? response.headers.raw() + : null, + body: resp && resp.body ? resp.body : null, + }, + }; +}; + +const lighthouseFetch = (monitor, url) => { + return new Promise((resolve, reject) => { + const lighthouseWorker = fork('./utils/lighthouse'); + const timeoutHandler = setTimeout(async () => { + await processLighthouseScan({ + data: { url }, + error: { message: 'TIMEOUT' }, + }); + }, 300000); + + lighthouseWorker.send(url); + lighthouseWorker.on('message', async result => { + await processLighthouseScan(result); + }); + + async function processLighthouseScan(result) { + clearTimeout(timeoutHandler); + lighthouseWorker.removeAllListeners(); + if (result.error) { + reject({ status: 'failed', ...result }); + } else { + resolve({ status: 'scanned', ...result }); + } + } + }); +}; From 0e97a25b1a09d5ae8a5d669a9c574615ae4000b4 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 02:07:39 +0100 Subject: [PATCH 02/22] lighthouse-runner --- backend/backend/api/lighthouse.js | 483 +++++++++++------- backend/backend/api/probe.js | 1 + .../middlewares/lighthouseAuthorization.js | 3 - backend/backend/services/lighthouseService.js | 175 ++++--- lighthouse-runner/workers/main.js | 2 +- lighthouse-runner/workers/urlMonitors.js | 125 +---- probe/workers/urlMonitors.js | 94 ++-- 7 files changed, 460 insertions(+), 423 deletions(-) diff --git a/backend/backend/api/lighthouse.js b/backend/backend/api/lighthouse.js index 59d9e7e8ef..da749e5f14 100644 --- a/backend/backend/api/lighthouse.js +++ b/backend/backend/api/lighthouse.js @@ -79,7 +79,6 @@ router.get('/monitors', isAuthorizedLighthouse, async function (req, res) { req.lighthouse.id, new Date(new Date().getTime() - 60 * 1000) ); - console.log("Get Lighthouse Monitors: ", monitors); //Update the lastAlive in the lighthouse servers list located in the status pages. if (monitors.length > 0) { const projectIds = {}; @@ -112,19 +111,27 @@ router.get('/monitors', isAuthorizedLighthouse, async function (req, res) { } }); -router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( +router.post('/ping/:monitorId', isAuthorizedLighthouse, async function( req, response ) { // let release; try { - console.log("Pinging :", req.body); - console.log("Pinging 3 :", req.lighthouse); + // const monitorId = req.body.monitor + // ? req.body.monitor._id.toString() + // : ''; + + // const mutex = getMutex(MUTEX_RESOURCES.MONITOR, monitorId); + // if (mutex) { + // release = await mutex.acquire(); + // } + const { monitor, res, resp, rawResp, + serverData, type, retryCount, } = req.body; @@ -135,188 +142,320 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( data = {}; let matchedCriterion; - if (type === 'url') { - const { - stat: validUp, - successReasons: upSuccessReasons, - failedReasons: upFailedReasons, - matchedCriterion: matchedUpCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.up - ? ProbeService.conditions( - monitor.type, - monitor.criteria.up, - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); - const { - stat: validDegraded, - successReasons: degradedSuccessReasons, - failedReasons: degradedFailedReasons, - matchedCriterion: matchedDegradedCriterion, - } = await (monitor && + console.log("The Lighthouse Monitor Probe Id: ", monitor); + if (type === 'api' || type === 'url') { + const { + stat: validUp, + successReasons: upSuccessReasons, + failedReasons: upFailedReasons, + matchedCriterion: matchedUpCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.up + ? ProbeService.conditions( + monitor.type, + monitor.criteria.up, + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); + const { + stat: validDegraded, + successReasons: degradedSuccessReasons, + failedReasons: degradedFailedReasons, + matchedCriterion: matchedDegradedCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.degraded - ? ProbeService.conditions( - monitor.type, - monitor.criteria.degraded, - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); - const { - stat: validDown, - successReasons: downSuccessReasons, - failedReasons: downFailedReasons, - matchedCriterion: matchedDownCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.down - ? ProbeService.conditions( - monitor.type, - [ - ...monitor.criteria.down.filter( - criterion => criterion.default !== true - ), - ], - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); + ? ProbeService.conditions( + monitor.type, + monitor.criteria.degraded, + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); + const { + stat: validDown, + successReasons: downSuccessReasons, + failedReasons: downFailedReasons, + matchedCriterion: matchedDownCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.down + ? ProbeService.conditions( + monitor.type, + [ + ...monitor.criteria.down.filter( + criterion => criterion.default !== true + ), + ], + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); - if (validUp) { - status = 'online'; - reason = upSuccessReasons; - matchedCriterion = matchedUpCriterion; - } else if (validDegraded) { - status = 'degraded'; - reason = [...degradedSuccessReasons, ...upFailedReasons]; - matchedCriterion = matchedDegradedCriterion; - } else if (validDown) { - matchedCriterion = matchedDownCriterion; - status = 'offline'; - reason = [ - ...downSuccessReasons, - ...degradedFailedReasons, - ...upFailedReasons, - ]; - } else { - status = 'offline'; - reason = [ - ...downFailedReasons, - ...degradedFailedReasons, - ...upFailedReasons, - ]; - if (monitor.criteria.down) { - matchedCriterion = monitor.criteria.down.find( - criterion => criterion.default === true - ); + if (validUp) { + status = 'online'; + reason = upSuccessReasons; + matchedCriterion = matchedUpCriterion; + } else if (validDegraded) { + status = 'degraded'; + reason = [...degradedSuccessReasons, ...upFailedReasons]; + matchedCriterion = matchedDegradedCriterion; + } else if (validDown) { + matchedCriterion = matchedDownCriterion; + status = 'offline'; + reason = [ + ...downSuccessReasons, + ...degradedFailedReasons, + ...upFailedReasons, + ]; + } else { + status = 'offline'; + reason = [ + ...downFailedReasons, + ...degradedFailedReasons, + ...upFailedReasons, + ]; + if (monitor.criteria.down) { + matchedCriterion = monitor.criteria.down.find( + criterion => criterion.default === true + ); + } } + data.status = status; + data.reason = reason; } - data.status = status; - data.reason = reason; - } - - data = req.body; - data.responseTime = res || 0; - data.responseStatus = resp && resp.status ? resp.status : null; - data.status = status; - data.sslCertificate = - resp && resp.sslCertificate ? resp.sslCertificate : null; - data.lighthouseScanStatus = - resp && resp.lighthouseScanStatus - ? resp.lighthouseScanStatus - : null; - data.performance = - resp && resp.performance ? resp.performance : null; - data.accessibility = - resp && resp.accessibility ? resp.accessibility : null; - data.bestPractices = - resp && resp.bestPractices ? resp.bestPractices : null; - data.seo = resp && resp.seo ? resp.seo : null; - data.pwa = resp && resp.pwa ? resp.pwa : null; - data.lighthouseData = - resp && resp.lighthouseData ? resp.lighthouseData : null; - data.retryCount = retryCount || 0; - data.reason = reason; - data.response = rawResp; - - - data.matchedCriterion = matchedCriterion; - console.log("Data before monitor update: ", data); - // update monitor to save the last matched criterion - await MonitorService.updateOneBy( - { - _id: monitor._id, - }, - { - lastMatchedCriterion: matchedCriterion, + if (type === 'ip') { + const { + stat: validUp, + successReasons: upSuccessReasons, + failedReasons: upFailedReasons, + matchedCriterion: matchedUpCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.up + ? ProbeService.conditions( + monitor.type, + monitor.criteria.up, + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); + const { + stat: validDown, + successReasons: downSuccessReasons, + failedReasons: downFailedReasons, + matchedCriterion: matchedDownCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.down + ? ProbeService.conditions( + monitor.type, + [ + ...monitor.criteria.down.filter( + criterion => criterion.default !== true + ), + ], + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); + if (validUp) { + status = 'online'; + reason = upSuccessReasons; + matchedCriterion = matchedUpCriterion; + } else if (validDown) { + matchedCriterion = matchedDownCriterion; + status = 'offline'; + reason = [...downSuccessReasons, null, ...upFailedReasons]; + } else { + status = 'offline'; + reason = [...downFailedReasons, null, ...upFailedReasons]; + if (monitor.criteria.down) { + matchedCriterion = monitor.criteria.down.find( + criterion => criterion.default === true + ); + } + } + data.status = status; + data.reason = reason; } - ); - data.monitorId = req.params.monitorId || monitor._id; - data.lighthouseId = req.lighthouse && req.lighthouse.id ? req.lighthouse.id : null; - data.reason = - data && data.reason && data.reason.length - ? data.reason.filter( - (item, pos, self) => self.indexOf(item) === pos - ) - : data.reason; - const index = - data.reason && data.reason.indexOf('Request Timed out'); - if (index > -1) { + + if (type === 'server-monitor') { + data = serverData; + const { + stat: validUp, + successReasons: upSuccessReasons, + failedReasons: upFailedReasons, + matchedCriterion: matchedUpCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.up + ? ProbeService.conditions( + monitor.type, + monitor.criteria.up, + data + ) + : { stat: false, successReasons: [], failedReasons: [] }); + const { + stat: validDegraded, + successReasons: degradedSuccessReasons, + failedReasons: degradedFailedReasons, + matchedCriterion: matchedDegradedCriterion, + } = await (monitor && + monitor.criteria && + monitor.criteria.degraded + ? ProbeService.conditions( + monitor.type, + monitor.criteria.degraded, + data + ) + : { stat: false, successReasons: [], failedReasons: [] }); + const { + stat: validDown, + successReasons: downSuccessReasons, + failedReasons: downFailedReasons, + matchedCriterion: matchedDownCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.down + ? ProbeService.conditions( + monitor.type, + [ + ...monitor.criteria.down.filter( + criterion => criterion.default !== true + ), + ], + data + ) + : { stat: false, successReasons: [], failedReasons: [] }); + + if (validUp) { + data.status = 'online'; + data.reason = upSuccessReasons; + matchedCriterion = matchedUpCriterion; + } else if (validDegraded) { + data.status = 'degraded'; + data.reason = [ + ...degradedSuccessReasons, + ...upFailedReasons, + ]; + matchedCriterion = matchedDegradedCriterion; + } else if (validDown) { + data.status = 'offline'; + data.reason = [ + ...downSuccessReasons, + ...degradedFailedReasons, + ...upFailedReasons, + ]; + matchedCriterion = matchedDownCriterion; + } else { + data.status = 'offline'; + data.reason = [ + ...downFailedReasons, + ...degradedFailedReasons, + ...upFailedReasons, + ]; + if (monitor.criteria.down) { + matchedCriterion = monitor.criteria.down.find( + criterion => criterion.default === true + ); + } + } + } else { + data = req.body; + data.responseTime = res || 0; + data.responseStatus = resp && resp.status ? resp.status : null; + data.status = status; + data.sslCertificate = + resp && resp.sslCertificate ? resp.sslCertificate : null; + data.lighthouseScanStatus = + resp && resp.lighthouseScanStatus + ? resp.lighthouseScanStatus + : null; + data.performance = + resp && resp.performance ? resp.performance : null; + data.accessibility = + resp && resp.accessibility ? resp.accessibility : null; + data.bestPractices = + resp && resp.bestPractices ? resp.bestPractices : null; + data.seo = resp && resp.seo ? resp.seo : null; + data.pwa = resp && resp.pwa ? resp.pwa : null; + data.lighthouseData = + resp && resp.lighthouseData ? resp.lighthouseData : null; + data.retryCount = retryCount || 0; + data.reason = reason; + data.response = rawResp; + } + + + data.matchedCriterion = matchedCriterion; + // update monitor to save the last matched criterion + await MonitorService.updateOneBy( + { + _id: monitor._id, + }, + { + lastMatchedCriterion: matchedCriterion, + } + ); + data.monitorId = req.params.monitorId || monitor._id; + data.probeId = monitor.pollTime && monitor.pollTime[1].probeId ? monitor.pollTime[1].probeId : null; + console.log("Data ProbeId: ", data.probeId); data.reason = data && data.reason && data.reason.length ? data.reason.filter( - item => !item.includes('Response Time is') - ) + (item, pos, self) => self.indexOf(item) === pos + ) : data.reason; - } - console.log("Data Lighthouse update: ", data); - if (data.lighthouseScanStatus) { - if (data.lighthouseScanStatus === 'scanning') { - await MonitorService.updateOneBy( - { _id: data.monitorId }, - { - lighthouseScanStatus: data.lighthouseScanStatus, - }, - { fetchLightHouse: true } - ); - await LighthouseLogService.updateAllLighthouseLogs( - data.monitor.projectId, - data.monitorId, - { scanning: true } - ); - } else { - await MonitorService.updateOneBy( - { _id: data.monitorId }, - { - lighthouseScannedAt: Date.now(), - lighthouseScanStatus: data.lighthouseScanStatus, // scanned || failed - lighthouseScannedBy: data.lighthouseId, - } - ); + const index = + data.reason && data.reason.indexOf('Request Timed out'); + if (index > -1) { + data.reason = + data && data.reason && data.reason.length + ? data.reason.filter( + item => !item.includes('Response Time is') + ) + : data.reason; } - } else { - if (data.lighthouseData) { - data.scanning = false; - log = await LighthouseService.saveLighthouseLog(data); + + if (data.lighthouseScanStatus) { + if (data.lighthouseScanStatus === 'scanning') { + await MonitorService.updateOneBy( + { _id: data.monitorId }, + { + lighthouseScanStatus: data.lighthouseScanStatus, + }, + { fetchLightHouse: true } + ); + await LighthouseLogService.updateAllLighthouseLogs( + data.monitor.projectId, + data.monitorId, + { scanning: true } + ); + } else { + await MonitorService.updateOneBy( + { _id: data.monitorId }, + { + lighthouseScannedAt: Date.now(), + lighthouseScanStatus: data.lighthouseScanStatus, // scanned || failed + lighthouseScannedBy: data.probeId, + } + ); + } } else { - data.matchedUpCriterion = - monitor && monitor.criteria && monitor.criteria.up; - data.matchedDownCriterion = - monitor && monitor.criteria && monitor.criteria.down; - data.matchedDegradedCriterion = - monitor && - monitor.criteria && - monitor.criteria.degraded; + if (data.lighthouseData) { + data.scanning = false; + log = await ProbeService.saveLighthouseLog(data); + } else { + data.matchedUpCriterion = + monitor && monitor.criteria && monitor.criteria.up; + data.matchedDownCriterion = + monitor && monitor.criteria && monitor.criteria.down; + data.matchedDegradedCriterion = + monitor && + monitor.criteria && + monitor.criteria.degraded; - log = await LighthouseService.saveMonitorLog(data); + log = await ProbeService.saveMonitorLog(data); + + } } - } - console.log("Sent Log: ", log); - console.log("Sent Response: ", response); - console.log("Sent Response: ", req); + return sendItemResponse(req, response, log); } catch (error) { return sendErrorResponse(req, response, error); diff --git a/backend/backend/api/probe.js b/backend/backend/api/probe.js index 4ec0d4bb29..b4e8361318 100755 --- a/backend/backend/api/probe.js +++ b/backend/backend/api/probe.js @@ -578,6 +578,7 @@ router.post('/ping/:monitorId', isAuthorizedProbe, async function( ) : data.reason; } + if (data.lighthouseScanStatus) { if (data.lighthouseScanStatus === 'scanning') { await MonitorService.updateOneBy( diff --git a/backend/backend/middlewares/lighthouseAuthorization.js b/backend/backend/middlewares/lighthouseAuthorization.js index a91be592dc..d974f08600 100644 --- a/backend/backend/middlewares/lighthouseAuthorization.js +++ b/backend/backend/middlewares/lighthouseAuthorization.js @@ -9,7 +9,6 @@ const CLUSTER_KEY = process.env.CLUSTER_KEY; module.exports = { isAuthorizedLighthouse: async function (req, res, next) { - console.log("Sent Values: ",req.headers); try { let lighthouseKey, lighthouseName, clusterKey, lighthouseVersion; @@ -70,7 +69,6 @@ lighthouseVersion = req.body.lighthouseversion; } - console.log("Light House key: ", lighthouseKey); let lighthouse = null; if (clusterKey && clusterKey === CLUSTER_KEY) { @@ -109,7 +107,6 @@ } req.lighthouse = {}; req.lighthouse.id = lighthouse._id; - console.log("Lighthouse ID: ", req.lighthouse); //await LighthouseService.updateLighthouseStatus(lighthouse._id); //Update lighthouse version diff --git a/backend/backend/services/lighthouseService.js b/backend/backend/services/lighthouseService.js index 7486fb3b27..ece3c309d9 100644 --- a/backend/backend/services/lighthouseService.js +++ b/backend/backend/services/lighthouseService.js @@ -67,84 +67,107 @@ module.exports = { throw error; } }, - - conditions: async (monitorType, con, payload, resp, response) => { - const status = resp - ? resp.status - ? resp.status - : resp.statusCode - ? resp.statusCode - : null - : null; - const body = resp && resp.body ? resp.body : null; - const queryParams = resp && resp.queryParams ? resp.queryParams : null; - const headers = resp && resp.headers ? resp.headers : null; - const sslCertificate = - resp && resp.sslCertificate ? resp.sslCertificate : null; - const successReasons = []; - const failedReasons = []; - - let eventOccurred = false; - let matchedCriterion; - - if (con && con.length) { - eventOccurred = await some(con, async condition => { - let stat = true; - if ( - condition && - condition.criteria && - condition.criteria.condition && - condition.criteria.condition === 'and' - ) { - stat = await checkAnd( - payload, - condition.criteria, - status, - body, - sslCertificate, - response, - successReasons, - failedReasons, - monitorType, - queryParams, - headers - ); - } else if ( - condition && - condition.criteria && - condition.criteria.condition && - condition.criteria.condition === 'or' - ) { - stat = await checkOr( - payload, - condition.criteria, - status, - body, - sslCertificate, - response, - successReasons, - failedReasons, - monitorType, - queryParams, - headers - ); - } - if (stat) { - matchedCriterion = condition; - return true; - } - - return false; + saveMonitorLog: async function(data) { + try { + const _this = this; + const monitorStatus = await MonitorStatusService.findOneBy({ + monitorId: data.monitorId, + lighthouseId: data.lighthouseId, }); - } + const lastStatus = + monitorStatus && monitorStatus.status + ? monitorStatus.status + : null; - return { - stat: eventOccurred, - successReasons, - failedReasons, - matchedCriterion, - }; + let log = await MonitorLogService.create(data); + if (!data.stopPingTimeUpdate) { + await MonitorService.updateMonitorPingTime(data.monitorId); + } + + // grab all the criteria in a monitor + const allCriteria = []; + if (data.matchedUpCriterion) { + data.matchedUpCriterion.forEach(criteria => + allCriteria.push(criteria) + ); + } + if (data.matchedDownCriterion) { + data.matchedDownCriterion.forEach(criteria => + allCriteria.push(criteria) + ); + } + if (data.matchedDegradedCriterion) { + data.matchedDegradedCriterion.forEach(criteria => + allCriteria.push(criteria) + ); + } + + if (!lastStatus || (lastStatus && lastStatus !== data.status)) { + // check if monitor has a previous status + // check if previous status is different from the current status + // if different, resolve last incident, create a new incident and monitor status + if (lastStatus) { + // check 3 times just to make sure + if ( + typeof data.retry === 'boolean' && + data.retryCount >= 0 && + data.retryCount < 3 + ) + return { retry: true, retryCount: data.retryCount }; + + await _this.incidentResolveOrAcknowledge(data, allCriteria); + } + + const incidentIdsOrRetry = await _this.incidentCreateOrUpdate( + data + ); + if (incidentIdsOrRetry.retry) return incidentIdsOrRetry; + + if ( + Array.isArray(incidentIdsOrRetry) && + incidentIdsOrRetry.length + ) { + data.incidentId = incidentIdsOrRetry[0]; + } + + await MonitorStatusService.create(data); + + if (incidentIdsOrRetry && incidentIdsOrRetry.length) { + log = await MonitorLogService.updateOneBy( + { _id: log._id }, + { incidentIds: incidentIdsOrRetry } + ); + } + } else { + // should make sure all unresolved incidents for the monitor is resolved + if (data.status === 'online') { + await _this.incidentResolveOrAcknowledge(data, allCriteria); + } + + const incidents = await IncidentService.findBy({ + 'monitors.monitorId': data.monitorId, + incidentType: data.status, + resolved: false, + }); + + const incidentIds = incidents.map(incident => incident._id); + + if (incidentIds && incidentIds.length) { + log = await MonitorLogService.updateOneBy( + { _id: log._id }, + { incidentIds } + ); + } + } + return log; + } catch (error) { + ErrorService.log('lighthouseService.saveMonitorLog', error); + throw error; + } }, + } const LighthouseModel = require('../models/lighthouse'); -const { some } = require('p-iteration'); \ No newline at end of file +const ErrorService = require('./errorService'); +const MonitorStatusService = require('./monitorStatusService'); +const MonitorLogService = require('./monitorLogService'); \ No newline at end of file diff --git a/lighthouse-runner/workers/main.js b/lighthouse-runner/workers/main.js index f1fa65230f..911d55c2a3 100644 --- a/lighthouse-runner/workers/main.js +++ b/lighthouse-runner/workers/main.js @@ -7,10 +7,10 @@ module.exports = { try { let monitors = await getApi('lighthouse/monitors'); monitors = JSON.parse(monitors.data); // parse the stringified data - console.log("The Data Monitor: ", monitors);console.log("The Data Monitor: ", monitors); await Promise.all( monitors.map(monitor => { if(monitor.type === 'url'){ + console.log("monitor get: ", monitor) return UrlMonitors.ping(monitor); } return null; diff --git a/lighthouse-runner/workers/urlMonitors.js b/lighthouse-runner/workers/urlMonitors.js index b77fefd055..ce2d94181d 100755 --- a/lighthouse-runner/workers/urlMonitors.js +++ b/lighthouse-runner/workers/urlMonitors.js @@ -18,34 +18,9 @@ const httpAgent = new http.Agent(); module.exports = { ping: async monitor => { - console.log("Received Monitor to Ping: ",monitor); try { if (monitor && monitor.type) { if (monitor.data.url) { - let retry = true; - let retryCount = 0; - while (retry) { - const { res, resp, rawResp } = await pingfetch( - monitor.data.url - ); - console.log("Res", res); - console.log("Resp", resp); - console.log("Raw Res", rawResp); - const response = await UrlService.ping(monitor._id, { - monitor, - res, - resp, - rawResp, - type: monitor.type, - retryCount, - }); - - if (response && !response.retry) { - retry = false; - } else { - retryCount++; - } - } const now = new Date().getTime(); const scanIntervalInDays = monitor.lighthouseScannedAt @@ -77,7 +52,7 @@ module.exports = { monitor, url ); - + console.log("Scanned Lighthouse :", resp); await UrlService.ping(monitor._id, { monitor, resp, @@ -110,104 +85,6 @@ module.exports = { }, }; -const pingfetch = async url => { - const now = new Date().getTime(); - let resp, res, response; - - try { - let sslCertificate, data; - const urlObject = new URL(url); - const headers = { - 'User-Agent': - 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36', - }; - try { - /* Try with a normal http / https agent. - If this fails we'll try with an agent which has - { - rejectUnauthorized: false, - } - - to check for self-signed SSL certs. - */ - - response = await fetch(url, { timeout: 500000, headers }); - res = new Date().getTime() - now; - data = await response.text(); - if (urlObject.protocol === 'https:') { - const certificate = await sslCert.get(urlObject.hostname); - if (certificate) { - sslCertificate = { - issuer: certificate.issuer, - expires: certificate.valid_to, - fingerprint: certificate.fingerprint, - selfSigned: false, - }; - } - } - } catch (e) { - /* Retry with an agent which has - - { - rejectUnauthorized: false, - } - - to check for self-signed SSL certs. - */ - - response = await fetch(url, { - timeout: 500000, - ...(url.startsWith('https') - ? { agent: httpsAgent } - : { agent: httpAgent }), - headers, - }); - res = new Date().getTime() - now; - data = await response.text(); - if (urlObject.protocol === 'https:') { - const certificate = await sslCert.get(urlObject.hostname); - if (certificate) { - sslCertificate = { - issuer: certificate.issuer, - expires: certificate.valid_to, - fingerprint: certificate.fingerprint, - selfSigned: e.code === 'DEPTH_ZERO_SELF_SIGNED_CERT', - }; - } - } - } - - resp = { status: response.status, body: data, sslCertificate }; - } catch (error) { - res = new Date().getTime() - now; - resp = { status: 408, body: error }; - } - - // this hard coded value will be removed soon - res = res / 100; - - return { - res, - resp, - rawResp: { - ok: response && response.ok ? response.ok : null, - status: - response && response.status - ? response.status - : resp && resp.status - ? resp.status - : null, - statusText: - response && response.statusText ? response.statusText : null, - headers: - response && response.headers && response.headers.raw() - ? response.headers.raw() - : null, - body: resp && resp.body ? resp.body : null, - }, - }; -}; - const lighthouseFetch = (monitor, url) => { return new Promise((resolve, reject) => { const lighthouseWorker = fork('./utils/lighthouse'); diff --git a/probe/workers/urlMonitors.js b/probe/workers/urlMonitors.js index 1d33cde21e..1827d1b1dc 100755 --- a/probe/workers/urlMonitors.js +++ b/probe/workers/urlMonitors.js @@ -27,7 +27,7 @@ module.exports = { const { res, resp, rawResp } = await pingfetch( monitor.data.url ); - + const response = await ApiService.ping(monitor._id, { monitor, res, @@ -36,7 +36,6 @@ module.exports = { type: monitor.type, retryCount, }); - if (response && !response.retry) { retry = false; } else { @@ -51,53 +50,54 @@ module.exports = { 'days' ) : -1; - if ( - (monitor.lighthouseScanStatus && - monitor.lighthouseScanStatus === 'scan') || - (monitor.lighthouseScanStatus && - monitor.lighthouseScanStatus === 'failed') || - ((!monitor.lighthouseScannedAt || - scanIntervalInDays > 0) && - (!monitor.lighthouseScanStatus || - monitor.lighthouseScanStatus !== 'scanning')) - ) { - await ApiService.ping(monitor._id, { - monitor, - resp: { lighthouseScanStatus: 'scanning' }, - }); + + // if ( + // (monitor.lighthouseScanStatus && + // monitor.lighthouseScanStatus === 'scan') || + // (monitor.lighthouseScanStatus && + // monitor.lighthouseScanStatus === 'failed') || + // ((!monitor.lighthouseScannedAt || + // scanIntervalInDays > 0) && + // (!monitor.lighthouseScanStatus || + // monitor.lighthouseScanStatus !== 'scanning')) + // ) { + // await ApiService.ping(monitor._id, { + // monitor, + // resp: { lighthouseScanStatus: 'scanning' }, + // }); - const sites = monitor.siteUrls; - let failedCount = 0; - for (const url of sites) { - try { - const resp = await lighthouseFetch( - monitor, - url - ); + // const sites = monitor.siteUrls; + // let failedCount = 0; + // for (const url of sites) { + // try { + // const resp = await lighthouseFetch( + // monitor, + // url + // ); + + // await ApiService.ping(monitor._id, { + // monitor, + // resp, + // }); + // } catch (error) { + // failedCount++; + // ErrorService.log( + // 'lighthouseFetch', + // error.error + // ); + // } + // } - await ApiService.ping(monitor._id, { - monitor, - resp, - }); - } catch (error) { - failedCount++; - ErrorService.log( - 'lighthouseFetch', - error.error - ); - } - } - - await ApiService.ping(monitor._id, { - monitor, - resp: { - lighthouseScanStatus: - failedCount === sites.length - ? 'failed' - : 'scanned', - }, - }); - } + // await ApiService.ping(monitor._id, { + // monitor, + // resp: { + // lighthouseScanStatus: + // failedCount === sites.length + // ? 'failed' + // : 'scanned', + // }, + // }); + // } } } } catch (error) { From fdbec9cb9b2e348eaa8e5f0969f7e7845f9fb2f5 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 02:18:40 +0100 Subject: [PATCH 03/22] lighthouse-runner --- backend/backend/api/lighthouse.js | 271 +++++++++--------------------- 1 file changed, 81 insertions(+), 190 deletions(-) diff --git a/backend/backend/api/lighthouse.js b/backend/backend/api/lighthouse.js index da749e5f14..dc523597c3 100644 --- a/backend/backend/api/lighthouse.js +++ b/backend/backend/api/lighthouse.js @@ -17,56 +17,9 @@ const isAuthorizedAdmin = require('../middlewares/clusterAuthorization') const sendErrorResponse = require('../middlewares/response').sendErrorResponse; const sendItemResponse = require('../middlewares/response').sendItemResponse; const sendListResponse = require('../middlewares/response').sendListResponse; -const getUser = require('../middlewares/user').getUser; -const { isAuthorized } = require('../middlewares/authorization'); -const storage = require('../middlewares/upload'); const { isAuthorizedLighthouse } = require('../middlewares/lighthouseAuthorization'); -router.post('/', getUser, isAuthorizedAdmin, async function (req, res) { - try { - const data = req.body; - const lighthouse = await LighthouseService.create(data); - return sendItemResponse(req, res, lighthouse); - } catch (error) { - return sendErrorResponse(req, res, error); - } -}); - -router.get('/', getUser, isAuthorizedAdmin, async function (req, res) { - try { - const skip = req.query.skip || 0; - const limit = req.query.limit || 0; - const lighthouse = await LighthouseService.findBy({}, limit, skip); - const count = await LighthouseService.countBy({}); - return sendListResponse(req, res, lighthouse, count); - } catch (error) { - return sendErrorResponse(req, res, error); - } -}); - -router.put('/:id', getUser, isAuthorizedAdmin, async function (req, res) { - try { - const data = req.body; - const lighthouse = await LighthouseService.updateOneBy( - { _id: req.params.id }, - data - ); - return sendItemResponse(req, res, lighthouse); - } catch (error) { - return sendErrorResponse(req, res, error); - } -}); - -router.delete('/:id', getUser, isAuthorizedAdmin, async function (req, res) { - try { - const lighthouse = await LighthouseService.deleteBy({ _id: req.params.id }); - return sendItemResponse(req, res, lighthouse); - } catch (error) { - return sendErrorResponse(req, res, error); - } -}); - // Route // Description: Updating profile setting. // Params: @@ -117,14 +70,6 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function( ) { // let release; try { - // const monitorId = req.body.monitor - // ? req.body.monitor._id.toString() - // : ''; - - // const mutex = getMutex(MUTEX_RESOURCES.MONITOR, monitorId); - // if (mutex) { - // release = await mutex.acquire(); - // } const { monitor, @@ -141,9 +86,8 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function( reason, data = {}; let matchedCriterion; - - console.log("The Lighthouse Monitor Probe Id: ", monitor); - if (type === 'api' || type === 'url') { + + if (type === 'url') { const { stat: validUp, successReasons: upSuccessReasons, @@ -225,138 +169,85 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function( data.status = status; data.reason = reason; } - if (type === 'ip') { - const { - stat: validUp, - successReasons: upSuccessReasons, - failedReasons: upFailedReasons, - matchedCriterion: matchedUpCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.up - ? ProbeService.conditions( - monitor.type, - monitor.criteria.up, - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); - const { - stat: validDown, - successReasons: downSuccessReasons, - failedReasons: downFailedReasons, - matchedCriterion: matchedDownCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.down - ? ProbeService.conditions( - monitor.type, - [ - ...monitor.criteria.down.filter( - criterion => criterion.default !== true - ), - ], - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); - if (validUp) { - status = 'online'; - reason = upSuccessReasons; - matchedCriterion = matchedUpCriterion; - } else if (validDown) { - matchedCriterion = matchedDownCriterion; - status = 'offline'; - reason = [...downSuccessReasons, null, ...upFailedReasons]; - } else { - status = 'offline'; - reason = [...downFailedReasons, null, ...upFailedReasons]; - if (monitor.criteria.down) { - matchedCriterion = monitor.criteria.down.find( - criterion => criterion.default === true - ); - } - } - data.status = status; - data.reason = reason; - } - if (type === 'server-monitor') { - data = serverData; - const { - stat: validUp, - successReasons: upSuccessReasons, - failedReasons: upFailedReasons, - matchedCriterion: matchedUpCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.up - ? ProbeService.conditions( - monitor.type, - monitor.criteria.up, - data - ) - : { stat: false, successReasons: [], failedReasons: [] }); - const { - stat: validDegraded, - successReasons: degradedSuccessReasons, - failedReasons: degradedFailedReasons, - matchedCriterion: matchedDegradedCriterion, - } = await (monitor && - monitor.criteria && - monitor.criteria.degraded - ? ProbeService.conditions( - monitor.type, - monitor.criteria.degraded, - data - ) - : { stat: false, successReasons: [], failedReasons: [] }); - const { - stat: validDown, - successReasons: downSuccessReasons, - failedReasons: downFailedReasons, - matchedCriterion: matchedDownCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.down - ? ProbeService.conditions( - monitor.type, - [ - ...monitor.criteria.down.filter( - criterion => criterion.default !== true - ), - ], - data - ) - : { stat: false, successReasons: [], failedReasons: [] }); + // if (type === 'server-monitor') { + // data = serverData; + // const { + // stat: validUp, + // successReasons: upSuccessReasons, + // failedReasons: upFailedReasons, + // matchedCriterion: matchedUpCriterion, + // } = await (monitor && monitor.criteria && monitor.criteria.up + // ? ProbeService.conditions( + // monitor.type, + // monitor.criteria.up, + // data + // ) + // : { stat: false, successReasons: [], failedReasons: [] }); + // const { + // stat: validDegraded, + // successReasons: degradedSuccessReasons, + // failedReasons: degradedFailedReasons, + // matchedCriterion: matchedDegradedCriterion, + // } = await (monitor && + // monitor.criteria && + // monitor.criteria.degraded + // ? ProbeService.conditions( + // monitor.type, + // monitor.criteria.degraded, + // data + // ) + // : { stat: false, successReasons: [], failedReasons: [] }); + // const { + // stat: validDown, + // successReasons: downSuccessReasons, + // failedReasons: downFailedReasons, + // matchedCriterion: matchedDownCriterion, + // } = await (monitor && monitor.criteria && monitor.criteria.down + // ? ProbeService.conditions( + // monitor.type, + // [ + // ...monitor.criteria.down.filter( + // criterion => criterion.default !== true + // ), + // ], + // data + // ) + // : { stat: false, successReasons: [], failedReasons: [] }); - if (validUp) { - data.status = 'online'; - data.reason = upSuccessReasons; - matchedCriterion = matchedUpCriterion; - } else if (validDegraded) { - data.status = 'degraded'; - data.reason = [ - ...degradedSuccessReasons, - ...upFailedReasons, - ]; - matchedCriterion = matchedDegradedCriterion; - } else if (validDown) { - data.status = 'offline'; - data.reason = [ - ...downSuccessReasons, - ...degradedFailedReasons, - ...upFailedReasons, - ]; - matchedCriterion = matchedDownCriterion; - } else { - data.status = 'offline'; - data.reason = [ - ...downFailedReasons, - ...degradedFailedReasons, - ...upFailedReasons, - ]; - if (monitor.criteria.down) { - matchedCriterion = monitor.criteria.down.find( - criterion => criterion.default === true - ); - } - } - } else { + // if (validUp) { + // data.status = 'online'; + // data.reason = upSuccessReasons; + // matchedCriterion = matchedUpCriterion; + // } else if (validDegraded) { + // data.status = 'degraded'; + // data.reason = [ + // ...degradedSuccessReasons, + // ...upFailedReasons, + // ]; + // matchedCriterion = matchedDegradedCriterion; + // } else if (validDown) { + // data.status = 'offline'; + // data.reason = [ + // ...downSuccessReasons, + // ...degradedFailedReasons, + // ...upFailedReasons, + // ]; + // matchedCriterion = matchedDownCriterion; + // } else { + // data.status = 'offline'; + // data.reason = [ + // ...downFailedReasons, + // ...degradedFailedReasons, + // ...upFailedReasons, + // ]; + // if (monitor.criteria.down) { + // matchedCriterion = monitor.criteria.down.find( + // criterion => criterion.default === true + // ); + // } + // } + // } else { data = req.body; data.responseTime = res || 0; data.responseStatus = resp && resp.status ? resp.status : null; @@ -380,7 +271,7 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function( data.retryCount = retryCount || 0; data.reason = reason; data.response = rawResp; - } + //} data.matchedCriterion = matchedCriterion; @@ -395,7 +286,7 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function( ); data.monitorId = req.params.monitorId || monitor._id; data.probeId = monitor.pollTime && monitor.pollTime[1].probeId ? monitor.pollTime[1].probeId : null; - console.log("Data ProbeId: ", data.probeId); + data.reason = data && data.reason && data.reason.length ? data.reason.filter( From fad4601effee8aa6ea2cdc1438a5ffda5f04d898 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 02:19:45 +0100 Subject: [PATCH 04/22] lighthouse-runner --- backend/backend/api/lighthouse.js | 419 ++++++++++++------------------ 1 file changed, 170 insertions(+), 249 deletions(-) diff --git a/backend/backend/api/lighthouse.js b/backend/backend/api/lighthouse.js index dc523597c3..47af489cf8 100644 --- a/backend/backend/api/lighthouse.js +++ b/backend/backend/api/lighthouse.js @@ -64,7 +64,7 @@ router.get('/monitors', isAuthorizedLighthouse, async function (req, res) { } }); -router.post('/ping/:monitorId', isAuthorizedLighthouse, async function( +router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( req, response ) { @@ -86,267 +86,188 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function( reason, data = {}; let matchedCriterion; - - if (type === 'url') { - const { - stat: validUp, - successReasons: upSuccessReasons, - failedReasons: upFailedReasons, - matchedCriterion: matchedUpCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.up - ? ProbeService.conditions( - monitor.type, - monitor.criteria.up, - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); - const { - stat: validDegraded, - successReasons: degradedSuccessReasons, - failedReasons: degradedFailedReasons, - matchedCriterion: matchedDegradedCriterion, - } = await (monitor && + + if (type === 'url') { + const { + stat: validUp, + successReasons: upSuccessReasons, + failedReasons: upFailedReasons, + matchedCriterion: matchedUpCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.up + ? ProbeService.conditions( + monitor.type, + monitor.criteria.up, + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); + const { + stat: validDegraded, + successReasons: degradedSuccessReasons, + failedReasons: degradedFailedReasons, + matchedCriterion: matchedDegradedCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.degraded - ? ProbeService.conditions( - monitor.type, - monitor.criteria.degraded, - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); - const { - stat: validDown, - successReasons: downSuccessReasons, - failedReasons: downFailedReasons, - matchedCriterion: matchedDownCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.down - ? ProbeService.conditions( - monitor.type, - [ - ...monitor.criteria.down.filter( - criterion => criterion.default !== true - ), - ], - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); + ? ProbeService.conditions( + monitor.type, + monitor.criteria.degraded, + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); + const { + stat: validDown, + successReasons: downSuccessReasons, + failedReasons: downFailedReasons, + matchedCriterion: matchedDownCriterion, + } = await (monitor && monitor.criteria && monitor.criteria.down + ? ProbeService.conditions( + monitor.type, + [ + ...monitor.criteria.down.filter( + criterion => criterion.default !== true + ), + ], + res, + resp, + rawResp + ) + : { stat: false, successReasons: [], failedReasons: [] }); - if (validUp) { - status = 'online'; - reason = upSuccessReasons; - matchedCriterion = matchedUpCriterion; - } else if (validDegraded) { - status = 'degraded'; - reason = [...degradedSuccessReasons, ...upFailedReasons]; - matchedCriterion = matchedDegradedCriterion; - } else if (validDown) { - matchedCriterion = matchedDownCriterion; - status = 'offline'; - reason = [ - ...downSuccessReasons, - ...degradedFailedReasons, - ...upFailedReasons, - ]; - } else { - status = 'offline'; - reason = [ - ...downFailedReasons, - ...degradedFailedReasons, - ...upFailedReasons, - ]; - if (monitor.criteria.down) { - matchedCriterion = monitor.criteria.down.find( - criterion => criterion.default === true - ); - } + if (validUp) { + status = 'online'; + reason = upSuccessReasons; + matchedCriterion = matchedUpCriterion; + } else if (validDegraded) { + status = 'degraded'; + reason = [...degradedSuccessReasons, ...upFailedReasons]; + matchedCriterion = matchedDegradedCriterion; + } else if (validDown) { + matchedCriterion = matchedDownCriterion; + status = 'offline'; + reason = [ + ...downSuccessReasons, + ...degradedFailedReasons, + ...upFailedReasons, + ]; + } else { + status = 'offline'; + reason = [ + ...downFailedReasons, + ...degradedFailedReasons, + ...upFailedReasons, + ]; + if (monitor.criteria.down) { + matchedCriterion = monitor.criteria.down.find( + criterion => criterion.default === true + ); } - data.status = status; - data.reason = reason; } - - // if (type === 'server-monitor') { - // data = serverData; - // const { - // stat: validUp, - // successReasons: upSuccessReasons, - // failedReasons: upFailedReasons, - // matchedCriterion: matchedUpCriterion, - // } = await (monitor && monitor.criteria && monitor.criteria.up - // ? ProbeService.conditions( - // monitor.type, - // monitor.criteria.up, - // data - // ) - // : { stat: false, successReasons: [], failedReasons: [] }); - // const { - // stat: validDegraded, - // successReasons: degradedSuccessReasons, - // failedReasons: degradedFailedReasons, - // matchedCriterion: matchedDegradedCriterion, - // } = await (monitor && - // monitor.criteria && - // monitor.criteria.degraded - // ? ProbeService.conditions( - // monitor.type, - // monitor.criteria.degraded, - // data - // ) - // : { stat: false, successReasons: [], failedReasons: [] }); - // const { - // stat: validDown, - // successReasons: downSuccessReasons, - // failedReasons: downFailedReasons, - // matchedCriterion: matchedDownCriterion, - // } = await (monitor && monitor.criteria && monitor.criteria.down - // ? ProbeService.conditions( - // monitor.type, - // [ - // ...monitor.criteria.down.filter( - // criterion => criterion.default !== true - // ), - // ], - // data - // ) - // : { stat: false, successReasons: [], failedReasons: [] }); + data.status = status; + data.reason = reason; + } - // if (validUp) { - // data.status = 'online'; - // data.reason = upSuccessReasons; - // matchedCriterion = matchedUpCriterion; - // } else if (validDegraded) { - // data.status = 'degraded'; - // data.reason = [ - // ...degradedSuccessReasons, - // ...upFailedReasons, - // ]; - // matchedCriterion = matchedDegradedCriterion; - // } else if (validDown) { - // data.status = 'offline'; - // data.reason = [ - // ...downSuccessReasons, - // ...degradedFailedReasons, - // ...upFailedReasons, - // ]; - // matchedCriterion = matchedDownCriterion; - // } else { - // data.status = 'offline'; - // data.reason = [ - // ...downFailedReasons, - // ...degradedFailedReasons, - // ...upFailedReasons, - // ]; - // if (monitor.criteria.down) { - // matchedCriterion = monitor.criteria.down.find( - // criterion => criterion.default === true - // ); - // } - // } - // } else { - data = req.body; - data.responseTime = res || 0; - data.responseStatus = resp && resp.status ? resp.status : null; - data.status = status; - data.sslCertificate = - resp && resp.sslCertificate ? resp.sslCertificate : null; - data.lighthouseScanStatus = - resp && resp.lighthouseScanStatus - ? resp.lighthouseScanStatus - : null; - data.performance = - resp && resp.performance ? resp.performance : null; - data.accessibility = - resp && resp.accessibility ? resp.accessibility : null; - data.bestPractices = - resp && resp.bestPractices ? resp.bestPractices : null; - data.seo = resp && resp.seo ? resp.seo : null; - data.pwa = resp && resp.pwa ? resp.pwa : null; - data.lighthouseData = - resp && resp.lighthouseData ? resp.lighthouseData : null; - data.retryCount = retryCount || 0; - data.reason = reason; - data.response = rawResp; - //} - + data = req.body; + data.responseTime = res || 0; + data.responseStatus = resp && resp.status ? resp.status : null; + data.status = status; + data.sslCertificate = + resp && resp.sslCertificate ? resp.sslCertificate : null; + data.lighthouseScanStatus = + resp && resp.lighthouseScanStatus + ? resp.lighthouseScanStatus + : null; + data.performance = + resp && resp.performance ? resp.performance : null; + data.accessibility = + resp && resp.accessibility ? resp.accessibility : null; + data.bestPractices = + resp && resp.bestPractices ? resp.bestPractices : null; + data.seo = resp && resp.seo ? resp.seo : null; + data.pwa = resp && resp.pwa ? resp.pwa : null; + data.lighthouseData = + resp && resp.lighthouseData ? resp.lighthouseData : null; + data.retryCount = retryCount || 0; + data.reason = reason; + data.response = rawResp; - data.matchedCriterion = matchedCriterion; - // update monitor to save the last matched criterion - await MonitorService.updateOneBy( - { - _id: monitor._id, - }, - { - lastMatchedCriterion: matchedCriterion, - } - ); - data.monitorId = req.params.monitorId || monitor._id; - data.probeId = monitor.pollTime && monitor.pollTime[1].probeId ? monitor.pollTime[1].probeId : null; - + + data.matchedCriterion = matchedCriterion; + // update monitor to save the last matched criterion + await MonitorService.updateOneBy( + { + _id: monitor._id, + }, + { + lastMatchedCriterion: matchedCriterion, + } + ); + data.monitorId = req.params.monitorId || monitor._id; + data.probeId = monitor.pollTime && monitor.pollTime[1].probeId ? monitor.pollTime[1].probeId : null; + + data.reason = + data && data.reason && data.reason.length + ? data.reason.filter( + (item, pos, self) => self.indexOf(item) === pos + ) + : data.reason; + const index = + data.reason && data.reason.indexOf('Request Timed out'); + if (index > -1) { data.reason = data && data.reason && data.reason.length ? data.reason.filter( - (item, pos, self) => self.indexOf(item) === pos - ) + item => !item.includes('Response Time is') + ) : data.reason; - const index = - data.reason && data.reason.indexOf('Request Timed out'); - if (index > -1) { - data.reason = - data && data.reason && data.reason.length - ? data.reason.filter( - item => !item.includes('Response Time is') - ) - : data.reason; - } - - if (data.lighthouseScanStatus) { - if (data.lighthouseScanStatus === 'scanning') { - await MonitorService.updateOneBy( - { _id: data.monitorId }, - { - lighthouseScanStatus: data.lighthouseScanStatus, - }, - { fetchLightHouse: true } - ); - await LighthouseLogService.updateAllLighthouseLogs( - data.monitor.projectId, - data.monitorId, - { scanning: true } - ); - } else { - await MonitorService.updateOneBy( - { _id: data.monitorId }, - { - lighthouseScannedAt: Date.now(), - lighthouseScanStatus: data.lighthouseScanStatus, // scanned || failed - lighthouseScannedBy: data.probeId, - } - ); - } - } else { - if (data.lighthouseData) { - data.scanning = false; - log = await ProbeService.saveLighthouseLog(data); - } else { - data.matchedUpCriterion = - monitor && monitor.criteria && monitor.criteria.up; - data.matchedDownCriterion = - monitor && monitor.criteria && monitor.criteria.down; - data.matchedDegradedCriterion = - monitor && - monitor.criteria && - monitor.criteria.degraded; + } - log = await ProbeService.saveMonitorLog(data); - - } + if (data.lighthouseScanStatus) { + if (data.lighthouseScanStatus === 'scanning') { + await MonitorService.updateOneBy( + { _id: data.monitorId }, + { + lighthouseScanStatus: data.lighthouseScanStatus, + }, + { fetchLightHouse: true } + ); + await LighthouseLogService.updateAllLighthouseLogs( + data.monitor.projectId, + data.monitorId, + { scanning: true } + ); + } else { + await MonitorService.updateOneBy( + { _id: data.monitorId }, + { + lighthouseScannedAt: Date.now(), + lighthouseScanStatus: data.lighthouseScanStatus, // scanned || failed + lighthouseScannedBy: data.probeId, + } + ); } - + } else { + if (data.lighthouseData) { + data.scanning = false; + log = await ProbeService.saveLighthouseLog(data); + } else { + data.matchedUpCriterion = + monitor && monitor.criteria && monitor.criteria.up; + data.matchedDownCriterion = + monitor && monitor.criteria && monitor.criteria.down; + data.matchedDegradedCriterion = + monitor && + monitor.criteria && + monitor.criteria.degraded; + + log = await ProbeService.saveMonitorLog(data); + + } + } + return sendItemResponse(req, response, log); } catch (error) { return sendErrorResponse(req, response, error); From b25822ffcec0385d33c74ccad1a579a9e23bd901 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 02:25:29 +0100 Subject: [PATCH 05/22] lighthouse-runner --- .../middlewares/lighthouseAuthorization.js | 3 +- backend/backend/services/lighthouseService.js | 102 +----------------- 2 files changed, 2 insertions(+), 103 deletions(-) diff --git a/backend/backend/middlewares/lighthouseAuthorization.js b/backend/backend/middlewares/lighthouseAuthorization.js index d974f08600..970295656a 100644 --- a/backend/backend/middlewares/lighthouseAuthorization.js +++ b/backend/backend/middlewares/lighthouseAuthorization.js @@ -107,8 +107,7 @@ } req.lighthouse = {}; req.lighthouse.id = lighthouse._id; - //await LighthouseService.updateLighthouseStatus(lighthouse._id); - + //Update lighthouse version const lighthouseValue = await LighthouseService.findOneBy({ lighthouseKey, diff --git a/backend/backend/services/lighthouseService.js b/backend/backend/services/lighthouseService.js index ece3c309d9..342eb74728 100644 --- a/backend/backend/services/lighthouseService.js +++ b/backend/backend/services/lighthouseService.js @@ -67,107 +67,7 @@ module.exports = { throw error; } }, - saveMonitorLog: async function(data) { - try { - const _this = this; - const monitorStatus = await MonitorStatusService.findOneBy({ - monitorId: data.monitorId, - lighthouseId: data.lighthouseId, - }); - const lastStatus = - monitorStatus && monitorStatus.status - ? monitorStatus.status - : null; - - let log = await MonitorLogService.create(data); - if (!data.stopPingTimeUpdate) { - await MonitorService.updateMonitorPingTime(data.monitorId); - } - - // grab all the criteria in a monitor - const allCriteria = []; - if (data.matchedUpCriterion) { - data.matchedUpCriterion.forEach(criteria => - allCriteria.push(criteria) - ); - } - if (data.matchedDownCriterion) { - data.matchedDownCriterion.forEach(criteria => - allCriteria.push(criteria) - ); - } - if (data.matchedDegradedCriterion) { - data.matchedDegradedCriterion.forEach(criteria => - allCriteria.push(criteria) - ); - } - - if (!lastStatus || (lastStatus && lastStatus !== data.status)) { - // check if monitor has a previous status - // check if previous status is different from the current status - // if different, resolve last incident, create a new incident and monitor status - if (lastStatus) { - // check 3 times just to make sure - if ( - typeof data.retry === 'boolean' && - data.retryCount >= 0 && - data.retryCount < 3 - ) - return { retry: true, retryCount: data.retryCount }; - - await _this.incidentResolveOrAcknowledge(data, allCriteria); - } - - const incidentIdsOrRetry = await _this.incidentCreateOrUpdate( - data - ); - if (incidentIdsOrRetry.retry) return incidentIdsOrRetry; - - if ( - Array.isArray(incidentIdsOrRetry) && - incidentIdsOrRetry.length - ) { - data.incidentId = incidentIdsOrRetry[0]; - } - - await MonitorStatusService.create(data); - - if (incidentIdsOrRetry && incidentIdsOrRetry.length) { - log = await MonitorLogService.updateOneBy( - { _id: log._id }, - { incidentIds: incidentIdsOrRetry } - ); - } - } else { - // should make sure all unresolved incidents for the monitor is resolved - if (data.status === 'online') { - await _this.incidentResolveOrAcknowledge(data, allCriteria); - } - - const incidents = await IncidentService.findBy({ - 'monitors.monitorId': data.monitorId, - incidentType: data.status, - resolved: false, - }); - - const incidentIds = incidents.map(incident => incident._id); - - if (incidentIds && incidentIds.length) { - log = await MonitorLogService.updateOneBy( - { _id: log._id }, - { incidentIds } - ); - } - } - return log; - } catch (error) { - ErrorService.log('lighthouseService.saveMonitorLog', error); - throw error; - } - }, } const LighthouseModel = require('../models/lighthouse'); -const ErrorService = require('./errorService'); -const MonitorStatusService = require('./monitorStatusService'); -const MonitorLogService = require('./monitorLogService'); \ No newline at end of file +const ErrorService = require('./errorService'); \ No newline at end of file From 488d2025031a0333a785300c938744e31325ac47 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 02:38:39 +0100 Subject: [PATCH 06/22] lighthouse-runner --- probe/workers/urlMonitors.js | 55 ------------------------------------ 1 file changed, 55 deletions(-) diff --git a/probe/workers/urlMonitors.js b/probe/workers/urlMonitors.js index 1827d1b1dc..b7affd4b4a 100755 --- a/probe/workers/urlMonitors.js +++ b/probe/workers/urlMonitors.js @@ -43,61 +43,6 @@ module.exports = { } } - const now = new Date().getTime(); - const scanIntervalInDays = monitor.lighthouseScannedAt - ? moment(now).diff( - moment(monitor.lighthouseScannedAt), - 'days' - ) - : -1; - - // if ( - // (monitor.lighthouseScanStatus && - // monitor.lighthouseScanStatus === 'scan') || - // (monitor.lighthouseScanStatus && - // monitor.lighthouseScanStatus === 'failed') || - // ((!monitor.lighthouseScannedAt || - // scanIntervalInDays > 0) && - // (!monitor.lighthouseScanStatus || - // monitor.lighthouseScanStatus !== 'scanning')) - // ) { - // await ApiService.ping(monitor._id, { - // monitor, - // resp: { lighthouseScanStatus: 'scanning' }, - // }); - - // const sites = monitor.siteUrls; - // let failedCount = 0; - // for (const url of sites) { - // try { - // const resp = await lighthouseFetch( - // monitor, - // url - // ); - - // await ApiService.ping(monitor._id, { - // monitor, - // resp, - // }); - // } catch (error) { - // failedCount++; - // ErrorService.log( - // 'lighthouseFetch', - // error.error - // ); - // } - // } - - // await ApiService.ping(monitor._id, { - // monitor, - // resp: { - // lighthouseScanStatus: - // failedCount === sites.length - // ? 'failed' - // : 'scanned', - // }, - // }); - // } } } } catch (error) { From eaebe1113f5364911df7899b97a66f76414f2ed2 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 02:39:25 +0100 Subject: [PATCH 07/22] lighthouse-runner --- probe/workers/urlMonitors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/probe/workers/urlMonitors.js b/probe/workers/urlMonitors.js index b7affd4b4a..da96b6d5ee 100755 --- a/probe/workers/urlMonitors.js +++ b/probe/workers/urlMonitors.js @@ -42,7 +42,7 @@ module.exports = { retryCount++; } } - + // Lighthouse Refactored } } } catch (error) { From ec9d62bd093e00dd9ba74cd66e5ebcf0aeb99a92 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 03:38:59 +0100 Subject: [PATCH 08/22] lighthouse-runner --- backend/backend/api/lighthouse.js | 5 ++--- lighthouse-runner/workers/main.js | 1 - lighthouse-runner/workers/urlMonitors.js | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/backend/backend/api/lighthouse.js b/backend/backend/api/lighthouse.js index 47af489cf8..a59ac4d191 100644 --- a/backend/backend/api/lighthouse.js +++ b/backend/backend/api/lighthouse.js @@ -76,7 +76,6 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( res, resp, rawResp, - serverData, type, retryCount, } = req.body; @@ -206,8 +205,8 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( } ); data.monitorId = req.params.monitorId || monitor._id; - data.probeId = monitor.pollTime && monitor.pollTime[1].probeId ? monitor.pollTime[1].probeId : null; - + let probeId = await ProbeService.findBy(); + data.probeId = probeId ? probeId[0]._id : null; data.reason = data && data.reason && data.reason.length ? data.reason.filter( diff --git a/lighthouse-runner/workers/main.js b/lighthouse-runner/workers/main.js index 911d55c2a3..91f2d04436 100644 --- a/lighthouse-runner/workers/main.js +++ b/lighthouse-runner/workers/main.js @@ -10,7 +10,6 @@ module.exports = { await Promise.all( monitors.map(monitor => { if(monitor.type === 'url'){ - console.log("monitor get: ", monitor) return UrlMonitors.ping(monitor); } return null; diff --git a/lighthouse-runner/workers/urlMonitors.js b/lighthouse-runner/workers/urlMonitors.js index ce2d94181d..4cc6910435 100755 --- a/lighthouse-runner/workers/urlMonitors.js +++ b/lighthouse-runner/workers/urlMonitors.js @@ -52,7 +52,7 @@ module.exports = { monitor, url ); - console.log("Scanned Lighthouse :", resp); + await UrlService.ping(monitor._id, { monitor, resp, From 4734e69505854d76d55b40a0aac1e028586b23ef Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 12:29:05 +0100 Subject: [PATCH 09/22] lighthouse-runner --- backend/backend/api/lighthouse.js | 4 +-- lighthouse-runner/workers/main.js | 10 ++++-- probe/utils/lighthouse.js | 59 ------------------------------- probe/workers/urlMonitors.js | 26 -------------- 4 files changed, 9 insertions(+), 90 deletions(-) delete mode 100644 probe/utils/lighthouse.js diff --git a/backend/backend/api/lighthouse.js b/backend/backend/api/lighthouse.js index a59ac4d191..101f9879d5 100644 --- a/backend/backend/api/lighthouse.js +++ b/backend/backend/api/lighthouse.js @@ -9,11 +9,9 @@ const LighthouseService = require('../services/LighthouseService'); const ProbeService = require('../services/ProbeService'); const MonitorService = require('../services/monitorService'); const ProjectService = require('../services/projectService'); +const MonitorLogService = require('../services/monitorLogService'); const LighthouseLogService = require('../services/lighthouseLogService'); const router = express.Router(); -const isAuthorizedAdmin = require('../middlewares/clusterAuthorization') - .isAuthorizedAdmin; - const sendErrorResponse = require('../middlewares/response').sendErrorResponse; const sendItemResponse = require('../middlewares/response').sendItemResponse; const sendListResponse = require('../middlewares/response').sendListResponse; diff --git a/lighthouse-runner/workers/main.js b/lighthouse-runner/workers/main.js index 91f2d04436..3b028c4b51 100644 --- a/lighthouse-runner/workers/main.js +++ b/lighthouse-runner/workers/main.js @@ -9,8 +9,14 @@ module.exports = { monitors = JSON.parse(monitors.data); // parse the stringified data await Promise.all( monitors.map(monitor => { - if(monitor.type === 'url'){ - return UrlMonitors.ping(monitor); + if(monitor.type === 'url' && monitor.pollTime && monitor.pollTime.length > 0){ + const probe = monitor.pollTime.filter(probe => probe.probeId); + if(probe.length > 0){ // This checks that the probe server is working + return UrlMonitors.ping(monitor); + }else{ + //eslint-disable-next-line + console.log("Please Make Sure Probe Server is Up and Running!") + } } return null; }) diff --git a/probe/utils/lighthouse.js b/probe/utils/lighthouse.js deleted file mode 100644 index dccf01a24e..0000000000 --- a/probe/utils/lighthouse.js +++ /dev/null @@ -1,59 +0,0 @@ -const lighthouse = require('lighthouse'); -const chromeLauncher = require('chrome-launcher'); -const ErrorService = require('./errorService'); - -function launchChromeAndRunLighthouse( - url, - options = { chromeFlags: ['--headless', '--disable-gpu', '--no-sandbox'] }, - config = null -) { - return chromeLauncher.launch(options).then(chrome => { - options.port = chrome.port; - return lighthouse(url, options, config).then(results => { - return chrome.kill().then(() => results.lhr); - }); - }); -} - -process.on('message', url => { - launchChromeAndRunLighthouse(url) - .then(results => { - const issues = {}; - const categories = results.categories; - const audits = results.audits; - for (const category in categories) { - const ids = categories[category].auditRefs.map( - auditRef => auditRef.id - ); - issues[category] = ids - .map(id => - audits[id] && - audits[id].score !== null && - audits[id].score < 1 - ? audits[id] - : id - ) - .filter(id => typeof id !== 'string'); - } - - const result = { - lighthouseData: { url, issues }, - performance: Math.ceil( - results.categories.performance.score * 100 - ), - accessibility: Math.ceil( - results.categories.accessibility.score * 100 - ), - bestPractices: Math.ceil( - results.categories['best-practices'].score * 100 - ), - seo: Math.ceil(results.categories.seo.score * 100), - pwa: Math.ceil(results.categories.pwa.score * 100), - }; - process.send(result); - }) - .catch(error => { - process.send({ data: { url }, error }); - ErrorService.log('launchChromeAndRunLighthouse', error); - }); -}); diff --git a/probe/workers/urlMonitors.js b/probe/workers/urlMonitors.js index da96b6d5ee..6164793672 100755 --- a/probe/workers/urlMonitors.js +++ b/probe/workers/urlMonitors.js @@ -150,29 +150,3 @@ const pingfetch = async url => { }; }; -const lighthouseFetch = (monitor, url) => { - return new Promise((resolve, reject) => { - const lighthouseWorker = fork('./utils/lighthouse'); - const timeoutHandler = setTimeout(async () => { - await processLighthouseScan({ - data: { url }, - error: { message: 'TIMEOUT' }, - }); - }, 300000); - - lighthouseWorker.send(url); - lighthouseWorker.on('message', async result => { - await processLighthouseScan(result); - }); - - async function processLighthouseScan(result) { - clearTimeout(timeoutHandler); - lighthouseWorker.removeAllListeners(); - if (result.error) { - reject({ status: 'failed', ...result }); - } else { - resolve({ status: 'scanned', ...result }); - } - } - }); -}; From abdf71ec8c289c0089b2a7f2d5bd800e7cf6baa0 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 12:56:08 +0100 Subject: [PATCH 10/22] lighthouse-runner --- docker-compose.dev.yml | 20 ++++++++++++++++ docker-compose.yml | 12 ++++++++++ lighthouse-runner/Dockerfile | 36 +++++++++++++++++++++++++++++ lighthouse-runner/Dockerfile.dev | 38 +++++++++++++++++++++++++++++++ lighthouse-runner/workers/main.js | 3 +-- 5 files changed, 107 insertions(+), 2 deletions(-) create mode 100755 lighthouse-runner/Dockerfile create mode 100644 lighthouse-runner/Dockerfile.dev diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 80f67fffd7..814cc46d03 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -282,5 +282,25 @@ services: # Use node modules of the container and not host system. # https://stackoverflow.com/questions/29181032/add-a-volume-to-docker-but-exclude-a-sub-folder - /usr/src/app/node_modules/ + lighthouse-runner: + ports: + - '3001:3001' + - '9241:9229' # Debugging port. + build: + context: ./lighthouse-runner + dockerfile: ./Dockerfile.dev + env_file: + - ./lighthouse-runner/.env + environment: + - PORT=3001 + - SERVER_URL=http://backend:3002 + - LIGHTHOUSE_NAME=US + - LIGHTHOUSE_KEY=test-key + - IS_SAAS_SERVICE=${IS_SAAS_SERVICE} + volumes: + - ./lighthouse-runner:/usr/src/app + # Use node modules of the container and not host system. + # https://stackoverflow.com/questions/29181032/add-a-volume-to-docker-but-exclude-a-sub-folder + - /usr/src/app/node_modules/ volumes: mongodata: diff --git a/docker-compose.yml b/docker-compose.yml index 880f8c42c2..bfe42c1510 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -192,6 +192,18 @@ services: - IS_SAAS_SERVICE=${IS_SAAS_SERVICE} depends_on: - backend + lighthouse-runner: + ports: + - '3001:3001' + build: ./lighthouse-runner + env_file: + - ./lighthouse-runner/.env + environment: + - PORT=3001 + - SERVER_URL=http://backend:3002 + - IS_SAAS_SERVICE=${IS_SAAS_SERVICE} + depends_on: + - backend volumes: mongodata: diff --git a/lighthouse-runner/Dockerfile b/lighthouse-runner/Dockerfile new file mode 100755 index 0000000000..a856d4e062 --- /dev/null +++ b/lighthouse-runner/Dockerfile @@ -0,0 +1,36 @@ +# +# Fyipe-backend Dockerfile +# + +# Pull base image nodejs image. +FROM node:16 + +#SET ENV Variables +ENV PRODUCTION=true +ENV CHROME_PATH=/usr/bin/google-chrome + +# Install Chrome. +RUN \ + wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \ + apt-get update && \ + apt-get install -y google-chrome-stable && \ + rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /usr/src/app + +WORKDIR /usr/src/app + +# Install app dependencies +COPY package*.json /usr/src/app/ +RUN npm ci --only=production + +# Bundle app source +COPY . /usr/src/app + +# Expose ports. +# - 3001: Lighthouse Runner +EXPOSE 3001 + +#Run the app +CMD [ "npm", "start"] diff --git a/lighthouse-runner/Dockerfile.dev b/lighthouse-runner/Dockerfile.dev new file mode 100644 index 0000000000..d91f63136f --- /dev/null +++ b/lighthouse-runner/Dockerfile.dev @@ -0,0 +1,38 @@ +# +# Fyipe-backend Dockerfile +# + +# Pull base image nodejs image. +FROM node:16 + +#SET ENV Variables +ENV CHROME_PATH=/usr/bin/google-chrome + +WORKDIR /usr/src/app + +# Install Chrome. +RUN \ + wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \ + apt-get update && \ + apt-get install -y google-chrome-stable && \ + rm -rf /var/lib/apt/lists/* + + +# Install app dependencies +RUN cd /usr/src/app + +# Copy package.json files +COPY ./package.json /usr/src/app/package.json +COPY ./package-lock.json /usr/src/app/package-lock.json + + +RUN npm ci + +# Expose ports. +# - 3001: Lighthouse Runner +EXPOSE 3001 + +#Run the app +CMD [ "npm", "run", "dev"] + diff --git a/lighthouse-runner/workers/main.js b/lighthouse-runner/workers/main.js index 3b028c4b51..69a08f8324 100644 --- a/lighthouse-runner/workers/main.js +++ b/lighthouse-runner/workers/main.js @@ -14,8 +14,7 @@ module.exports = { if(probe.length > 0){ // This checks that the probe server is working return UrlMonitors.ping(monitor); }else{ - //eslint-disable-next-line - console.log("Please Make Sure Probe Server is Up and Running!") + ErrorService.log('getApi',"Please Make Sure Probe Server is Online.") } } return null; From c179b498457b6541d301f028e055db177debf1bb Mon Sep 17 00:00:00 2001 From: David Adewole Date: Wed, 30 Jun 2021 13:03:50 +0100 Subject: [PATCH 11/22] lighthouse-runner --- accounts/.env | 4 ++-- backend/.env | 4 ++-- dashboard/.env | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accounts/.env b/accounts/.env index 039551cc8b..4fe4557e50 100644 --- a/accounts/.env +++ b/accounts/.env @@ -4,6 +4,6 @@ STRIPE_PUBLIC_KEY=pk_test_UynUDrFmbBmFVgJXd9EZCvBj00QAVpdwPv AMPLITUDE_PUBLIC_KEY=cb70632f45c1ca7fe6180812c0d6494a SKIP_PREFLIGHT_CHECK=true PUBLIC_URL=/accounts -REACT_APP_IS_SAAS_SERVICE=true -IS_SAAS_SERVICE=true +#REACT_APP_IS_SAAS_SERVICE=true +#IS_SAAS_SERVICE=true #REACT_APP_DISABLE_SIGNUP=true diff --git a/backend/.env b/backend/.env index 33552de80e..c271bacb24 100755 --- a/backend/.env +++ b/backend/.env @@ -10,9 +10,9 @@ MONGO_URL=mongodb://localhost:27017/fyipedb REDIS_HOST=localhost CLUSTER_KEY=f414c23b4cdf4e84a6a66ecfd528eff2 TEST_TWILIO_NUMBER=+919910568840 -IS_SAAS_SERVICE=true +#IS_SAAS_SERVICE=true ENCRYPTION_KEY=01234567890123456789012345678901 -IS_TESTING=true +#IS_TESTING=true PUSHNOTIFICATION_PRIVATE_KEY=8aXTsH48-cegK-xBApLxxOezCOZIjaWpg81Dny2zbio PUSHNOTIFICATION_PUBLIC_KEY=BFAPbOTTU14VbTe_dnoYlVnOPLKUNm8GYmC50n3i4Ps64sk1Xqx8e894Clrscn1L2PsQ8-l4SsJVw7NRg4cx69Y PUSHNOTIFICATION_URL=mailto:support@fyipe.com diff --git a/dashboard/.env b/dashboard/.env index 4c910fefeb..c26c818803 100644 --- a/dashboard/.env +++ b/dashboard/.env @@ -4,8 +4,8 @@ STRIPE_PUBLIC_KEY=pk_test_UynUDrFmbBmFVgJXd9EZCvBj00QAVpdwPv AMPLITUDE_PUBLIC_KEY=4b76c47248f969446af69dfdbf687d90 SKIP_PREFLIGHT_CHECK=true PUBLIC_URL=/dashboard -REACT_APP_IS_SAAS_SERVICE=true -IS_SAAS_SERVICE=true +#REACT_APP_IS_SAAS_SERVICE=true +#IS_SAAS_SERVICE=true REACT_APP_VERSION=$npm_package_version REACT_APP_PUSHNOTIFICATION_PUBLIC_KEY=BFAPbOTTU14VbTe_dnoYlVnOPLKUNm8GYmC50n3i4Ps64sk1Xqx8e894Clrscn1L2PsQ8-l4SsJVw7NRg4cx69Y STATUSPAGE_DOMAIN=staging-statuspage.fyipe.com \ No newline at end of file From ea017e3ed7b164f67c06e12477e558e53e1cae71 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Thu, 1 Jul 2021 14:28:17 +0100 Subject: [PATCH 12/22] lighthouse-runner --- accounts/.env | 4 +- backend/.env | 4 +- backend/backend/api/lighthouse.js | 231 +++--------------- .../middlewares/lighthouseAuthorization.js | 106 +------- backend/backend/models/lighthouse.js | 21 -- backend/backend/services/lighthouseService.js | 73 ------ backend/backend/services/monitorService.js | 172 +++++-------- dashboard/.env | 4 +- docker-compose.dev.yml | 6 +- docker-compose.yml | 4 +- lighthouse-runner/.env | 2 - lighthouse-runner/Dockerfile | 4 +- lighthouse-runner/Dockerfile.dev | 4 +- lighthouse-runner/index.js | 6 +- lighthouse-runner/utils/api.js | 3 - lighthouse-runner/utils/config.js | 2 - lighthouse-runner/workers/main.js | 2 + lighthouse-runner/workers/urlMonitors.js | 14 +- probe/workers/urlMonitors.js | 1 - 19 files changed, 118 insertions(+), 545 deletions(-) delete mode 100644 backend/backend/models/lighthouse.js delete mode 100644 backend/backend/services/lighthouseService.js diff --git a/accounts/.env b/accounts/.env index 4fe4557e50..039551cc8b 100644 --- a/accounts/.env +++ b/accounts/.env @@ -4,6 +4,6 @@ STRIPE_PUBLIC_KEY=pk_test_UynUDrFmbBmFVgJXd9EZCvBj00QAVpdwPv AMPLITUDE_PUBLIC_KEY=cb70632f45c1ca7fe6180812c0d6494a SKIP_PREFLIGHT_CHECK=true PUBLIC_URL=/accounts -#REACT_APP_IS_SAAS_SERVICE=true -#IS_SAAS_SERVICE=true +REACT_APP_IS_SAAS_SERVICE=true +IS_SAAS_SERVICE=true #REACT_APP_DISABLE_SIGNUP=true diff --git a/backend/.env b/backend/.env index c271bacb24..33552de80e 100755 --- a/backend/.env +++ b/backend/.env @@ -10,9 +10,9 @@ MONGO_URL=mongodb://localhost:27017/fyipedb REDIS_HOST=localhost CLUSTER_KEY=f414c23b4cdf4e84a6a66ecfd528eff2 TEST_TWILIO_NUMBER=+919910568840 -#IS_SAAS_SERVICE=true +IS_SAAS_SERVICE=true ENCRYPTION_KEY=01234567890123456789012345678901 -#IS_TESTING=true +IS_TESTING=true PUSHNOTIFICATION_PRIVATE_KEY=8aXTsH48-cegK-xBApLxxOezCOZIjaWpg81Dny2zbio PUSHNOTIFICATION_PUBLIC_KEY=BFAPbOTTU14VbTe_dnoYlVnOPLKUNm8GYmC50n3i4Ps64sk1Xqx8e894Clrscn1L2PsQ8-l4SsJVw7NRg4cx69Y PUSHNOTIFICATION_URL=mailto:support@fyipe.com diff --git a/backend/backend/api/lighthouse.js b/backend/backend/api/lighthouse.js index 101f9879d5..7603b66957 100644 --- a/backend/backend/api/lighthouse.js +++ b/backend/backend/api/lighthouse.js @@ -5,11 +5,8 @@ */ const express = require('express'); -const LighthouseService = require('../services/LighthouseService'); const ProbeService = require('../services/ProbeService'); const MonitorService = require('../services/monitorService'); -const ProjectService = require('../services/projectService'); -const MonitorLogService = require('../services/monitorLogService'); const LighthouseLogService = require('../services/lighthouseLogService'); const router = express.Router(); const sendErrorResponse = require('../middlewares/response').sendErrorResponse; @@ -26,31 +23,8 @@ const { isAuthorizedLighthouse } = require('../middlewares/lighthouseAuthorizati router.get('/monitors', isAuthorizedLighthouse, async function (req, res) { try { - const monitors = await MonitorService.getUrlMonitors( - req.lighthouse.id, - new Date(new Date().getTime() - 60 * 1000) - ); - //Update the lastAlive in the lighthouse servers list located in the status pages. - if (monitors.length > 0) { - const projectIds = {}; - for (const monitor of monitors) { - const project = await ProjectService.findOneBy({ - _id: monitor.projectId, - }); - const projectId = project - ? project.parentProjectId - ? project.parentProjectId._id - : project._id - : monitor.projectId; - projectIds[projectId] = true; - } - for (const projectId of Object.keys(projectIds)) { - const lighthouse = await LighthouseService.findOneBy({ - _id: req.lighthouse.id, - }); - global.io.emit(`updatelighthouse-${projectId}`, lighthouse); - } - } + const monitors = await MonitorService.getUrlMonitors(); + return sendListResponse( req, res, @@ -66,115 +40,17 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( req, response ) { - // let release; try { - const { monitor, - res, resp, - rawResp, - type, - retryCount, } = req.body; - - let status, - log, - reason, - data = {}; - let matchedCriterion; - - if (type === 'url') { - const { - stat: validUp, - successReasons: upSuccessReasons, - failedReasons: upFailedReasons, - matchedCriterion: matchedUpCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.up - ? ProbeService.conditions( - monitor.type, - monitor.criteria.up, - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); - const { - stat: validDegraded, - successReasons: degradedSuccessReasons, - failedReasons: degradedFailedReasons, - matchedCriterion: matchedDegradedCriterion, - } = await (monitor && - monitor.criteria && - monitor.criteria.degraded - ? ProbeService.conditions( - monitor.type, - monitor.criteria.degraded, - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); - const { - stat: validDown, - successReasons: downSuccessReasons, - failedReasons: downFailedReasons, - matchedCriterion: matchedDownCriterion, - } = await (monitor && monitor.criteria && monitor.criteria.down - ? ProbeService.conditions( - monitor.type, - [ - ...monitor.criteria.down.filter( - criterion => criterion.default !== true - ), - ], - res, - resp, - rawResp - ) - : { stat: false, successReasons: [], failedReasons: [] }); - - if (validUp) { - status = 'online'; - reason = upSuccessReasons; - matchedCriterion = matchedUpCriterion; - } else if (validDegraded) { - status = 'degraded'; - reason = [...degradedSuccessReasons, ...upFailedReasons]; - matchedCriterion = matchedDegradedCriterion; - } else if (validDown) { - matchedCriterion = matchedDownCriterion; - status = 'offline'; - reason = [ - ...downSuccessReasons, - ...degradedFailedReasons, - ...upFailedReasons, - ]; - } else { - status = 'offline'; - reason = [ - ...downFailedReasons, - ...degradedFailedReasons, - ...upFailedReasons, - ]; - if (monitor.criteria.down) { - matchedCriterion = monitor.criteria.down.find( - criterion => criterion.default === true - ); - } - } - data.status = status; - data.reason = reason; - } + console.log("Lighthouse Ping body: ", req.body); + let log, data = {}; data = req.body; - data.responseTime = res || 0; - data.responseStatus = resp && resp.status ? resp.status : null; - data.status = status; - data.sslCertificate = - resp && resp.sslCertificate ? resp.sslCertificate : null; data.lighthouseScanStatus = - resp && resp.lighthouseScanStatus + resp && (resp.lighthouseScanStatus) ? resp.lighthouseScanStatus : null; data.performance = @@ -187,91 +63,40 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( data.pwa = resp && resp.pwa ? resp.pwa : null; data.lighthouseData = resp && resp.lighthouseData ? resp.lighthouseData : null; - data.retryCount = retryCount || 0; - data.reason = reason; - data.response = rawResp; - - - data.matchedCriterion = matchedCriterion; - // update monitor to save the last matched criterion - await MonitorService.updateOneBy( - { - _id: monitor._id, - }, - { - lastMatchedCriterion: matchedCriterion, - } - ); data.monitorId = req.params.monitorId || monitor._id; let probeId = await ProbeService.findBy(); data.probeId = probeId ? probeId[0]._id : null; - data.reason = - data && data.reason && data.reason.length - ? data.reason.filter( - (item, pos, self) => self.indexOf(item) === pos - ) - : data.reason; - const index = - data.reason && data.reason.indexOf('Request Timed out'); - if (index > -1) { - data.reason = - data && data.reason && data.reason.length - ? data.reason.filter( - item => !item.includes('Response Time is') - ) - : data.reason; - } - - if (data.lighthouseScanStatus) { - if (data.lighthouseScanStatus === 'scanning') { - await MonitorService.updateOneBy( - { _id: data.monitorId }, - { - lighthouseScanStatus: data.lighthouseScanStatus, - }, - { fetchLightHouse: true } - ); - await LighthouseLogService.updateAllLighthouseLogs( - data.monitor.projectId, - data.monitorId, - { scanning: true } - ); - } else { - await MonitorService.updateOneBy( - { _id: data.monitorId }, - { - lighthouseScannedAt: Date.now(), - lighthouseScanStatus: data.lighthouseScanStatus, // scanned || failed - lighthouseScannedBy: data.probeId, - } - ); - } + + if (data.lighthouseScanStatus === 'scanning') { + await MonitorService.updateOneBy( + { _id: data.monitorId }, + { + lighthouseScanStatus: data.lighthouseScanStatus, + }, + { fetchLightHouse: true } + ); + await LighthouseLogService.updateAllLighthouseLogs( + data.monitor.projectId, + data.monitorId, + { scanning: true } + ); } else { - if (data.lighthouseData) { + await MonitorService.updateOneBy( + { _id: data.monitorId }, + { + lighthouseScannedAt: Date.now(), + lighthouseScanStatus: data.lighthouseScanStatus, // scanned || failed + lighthouseScannedBy: data.probeId, + } + ); + if (data.lighthouseData) { // The scanned result are published data.scanning = false; log = await ProbeService.saveLighthouseLog(data); - } else { - data.matchedUpCriterion = - monitor && monitor.criteria && monitor.criteria.up; - data.matchedDownCriterion = - monitor && monitor.criteria && monitor.criteria.down; - data.matchedDegradedCriterion = - monitor && - monitor.criteria && - monitor.criteria.degraded; - - log = await ProbeService.saveMonitorLog(data); - } } - return sendItemResponse(req, response, log); } catch (error) { return sendErrorResponse(req, response, error); - } finally { - // if (release) { - // release(); - // } } }); diff --git a/backend/backend/middlewares/lighthouseAuthorization.js b/backend/backend/middlewares/lighthouseAuthorization.js index 970295656a..6af40c5fbf 100644 --- a/backend/backend/middlewares/lighthouseAuthorization.js +++ b/backend/backend/middlewares/lighthouseAuthorization.js @@ -3,54 +3,17 @@ * Copyright HackerBay, Inc. * */ - const LighthouseService = require('../services/lighthouseService'); const sendErrorResponse = require('../middlewares/response').sendErrorResponse; const ErrorService = require('../services/errorService'); - const CLUSTER_KEY = process.env.CLUSTER_KEY; module.exports = { - isAuthorizedLighthouse: async function (req, res, next) { - + isAuthorizedLighthouse: async function(req, res, next) { try { - let lighthouseKey, lighthouseName, clusterKey, lighthouseVersion; - - if (req.params.lighthousekey) { - lighthouseKey = req.params.lighthousekey; - } else if (req.query.lighthouseKey) { - lighthouseKey = req.query.lighthousekey; - } else if (req.headers['lighthousekey']) { - lighthouseKey = req.headers['lighthousekey']; - } else if (req.headers['lighthousekey']) { - lighthouseKey = req.headers['lighthousekey']; - } else if (req.body.lighthouseKey) { - lighthouseKey = req.body.lighthouseKey; - } else { - return sendErrorResponse(req, res, { - code: 400, - message: 'lighthouse Key not found.', - }); - } - - if (req.params.lighthousename) { - lighthouseName = req.params.lighthousename; - } else if (req.query.lighthousename) { - lighthouseName = req.query.lighthousename; - } else if (req.headers['lighthousename']) { - lighthouseName = req.headers['lighthousename']; - } else if (req.headers['lighthousename']) { - lighthouseName = req.headers['lighthousename']; - } else if (req.body.lighthouseName) { - lighthouseName = req.body.lighthousename; - } else { - return sendErrorResponse(req, res, { - code: 400, - message: 'lighthouse Name not found.', - }); - } + let clusterKey; if (req.params.clusterKey) { - clusterKey = req.params.clusterkey; + clusterKey = req.params.clusterKey; } else if (req.query.clusterKey) { - clusterKey = req.query.clusterkey; + clusterKey = req.query.clusterKey; } else if (req.headers['clusterKey']) { clusterKey = req.headers['clusterKey']; } else if (req.headers['clusterkey']) { @@ -59,70 +22,13 @@ clusterKey = req.body.clusterKey; } - if (req.params.lighthouseversion) { - lighthouseVersion = req.params.lighthouseversion; - } else if (req.query.lighthouseversion) { - lighthouseVersion = req.query.lighthouseversion; - } else if (req.headers['lighthouseversion']) { - lighthouseVersion = req.headers['lighthouseversion']; - } else if (req.body.lighthouseversion) { - lighthouseVersion = req.body.lighthouseversion; - } - - let lighthouse = null; - - if (clusterKey && clusterKey === CLUSTER_KEY) { - // if cluster key matches then just query by lighthouse name, - // because if the lighthouse key does not match, we can update lighthouse key later - // without updating mongodb database manually. - lighthouse = await LighthouseService.findOneBy({ lighthouseName }); - } else { - lighthouse = await LighthouseService.findOneBy({ lighthouseKey, lighthouseName }); - } - - if (!lighthouse && (!clusterKey || clusterKey !== CLUSTER_KEY)) { + if (!clusterKey ) { return sendErrorResponse(req, res, { code: 400, - message: 'lighthouse key and lighthouse name do not match.', + message: 'Authorization Rejected.', }); } - if (!lighthouse) { - //create a new lighthouse. - lighthouse = await LighthouseService.create({ - lighthouseKey, - lighthouseName, - lighthouseVersion, - }); - } - - if (lighthouse.lighthouseKey !== lighthouseKey) { - //update lighthouse key becasue it does not match. - await LighthouseService.updateOneBy( - { - lighthouseName, - }, - { lighthouseKey } - ); - } - req.lighthouse = {}; - req.lighthouse.id = lighthouse._id; - - //Update lighthouse version - const lighthouseValue = await LighthouseService.findOneBy({ - lighthouseKey, - lighthouseName, - }); - - if (!lighthouseValue.version || lighthouseValue.version !== lighthouseVersion) { - await LighthouseService.updateOneBy( - { - lighthouseName, - }, - { version: lighthouseVersion } - ); - } - next(); } catch (error) { ErrorService.log('lighthouseAuthorization.isAuthorizedLighthouse', error); diff --git a/backend/backend/models/lighthouse.js b/backend/backend/models/lighthouse.js deleted file mode 100644 index 49c4caf524..0000000000 --- a/backend/backend/models/lighthouse.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * - * Copyright HackerBay, Inc. - * - */ - - const mongoose = require('../config/db'); - - const Schema = mongoose.Schema; - const lighthouseSchema = new Schema({ - createdAt: { type: Date, default: Date.now }, - lighthouseKey: { type: String }, - lighthouseName: { type: String }, - version: { type: String }, - lastAlive: { type: Date, default: Date.now }, - deleted: { type: Boolean, default: false }, - deletedAt: { type: Date }, - }); - - module.exports = mongoose.model('lighthouse', lighthouseSchema); - \ No newline at end of file diff --git a/backend/backend/services/lighthouseService.js b/backend/backend/services/lighthouseService.js deleted file mode 100644 index 342eb74728..0000000000 --- a/backend/backend/services/lighthouseService.js +++ /dev/null @@ -1,73 +0,0 @@ -module.exports = { - create: async function(data) { - try { - const _this = this; - let lighthouseKey; - if (data.lighthouseKey) { - lighthouseKey = data.lighthouseKey; - } else { - lighthouseKey = uuidv1(); - } - const storedlighthouse = await _this.findOneBy({ - lighthouseName: data.lighthouseName, - }); - if (storedlighthouse && storedlighthouse.lighthouseName) { - const error = new Error('lighthouse name already exists.'); - error.code = 400; - ErrorService.log('lighthouse.create', error); - throw error; - } else { - const lighthouse = new LighthouseModel(); - lighthouse.lighthouseKey = lighthouseKey; - lighthouse.lighthouseName = data.lighthouseName; - lighthouse.version = data.lighthouseVersion; - const savedlighthouse = await lighthouse.save(); - return savedlighthouse; - } - } catch (error) { - ErrorService.log('lighthouseService.create', error); - throw error; - } - }, - - updateOneBy: async function(query, data) { - try { - if (!query) { - query = {}; - } - - query.deleted = false; - const lighthouse = await LighthouseModel.findOneAndUpdate( - query, - { $set: data }, - { - new: true, - } - ); - return lighthouse; - } catch (error) { - ErrorService.log('lighthouseService.updateOneBy', error); - throw error; - } - }, - - findOneBy: async function(query) { - try { - if (!query) { - query = {}; - } - - query.deleted = false; - const lighthouse = await LighthouseModel.findOne(query, { - deleted: false, - }).lean(); - return lighthouse; - } catch (error) { - ErrorService.log('lighthouseService.findOneBy', error); - throw error; - } - }, - -} -const LighthouseModel = require('../models/lighthouse'); -const ErrorService = require('./errorService'); \ No newline at end of file diff --git a/backend/backend/services/monitorService.js b/backend/backend/services/monitorService.js index 81d86b6129..e3d2e4b531 100755 --- a/backend/backend/services/monitorService.js +++ b/backend/backend/services/monitorService.js @@ -5,7 +5,7 @@ module.exports = { //Params: //Param 1: data: MonitorModal. //Returns: promise with monitor model or error. - create: async function(data) { + create: async function (data) { try { const _this = this; let subProject = null; @@ -74,8 +74,8 @@ module.exports = { plan.category === 'Startup' ? 5 : plan.category === 'Growth' - ? 10 - : 0; + ? 10 + : 0; if ( count < userCount * monitorCount || !IS_SAAS_SERVICE || @@ -178,7 +178,7 @@ module.exports = { } }, - updateOneBy: async function(query, data, unsetData) { + updateOneBy: async function (query, data, unsetData) { const _this = this; try { @@ -254,7 +254,7 @@ module.exports = { } }, - updateBy: async function(query, data) { + updateBy: async function (query, data) { try { if (!query) { query = {}; @@ -354,7 +354,7 @@ module.exports = { } }, - deleteBy: async function(query, userId) { + deleteBy: async function (query, userId) { try { if (!query) { query = {}; @@ -695,9 +695,8 @@ module.exports = { } }, - async getUrlMonitors(lighthouseId, date) { + async getUrlMonitors() { try { - const newdate = new Date(); const monitors = await MonitorModel.find({ $and: [ { @@ -707,73 +706,28 @@ module.exports = { { $or: [ { - $and: [ - { - type: { - $in: [ - 'url', - ], - }, - }, - { - $or: [ - { - pollTime: { - $elemMatch: { - lighthouseId, - date: { $lt: date }, - }, - }, - }, - { - //pollTime doesn't include the probeId yet. - pollTime: { - $not: { - $elemMatch: { - lighthouseId, - }, - }, - }, - }, - ], - }, - ], + lighthouseScanStatus: { + $exists: false, + } }, - ], + { + lighthouseScanStatus: { + $exists: true, + $nin: ['scanning', 'scanned'] + } + } + ] + }, + { + type: { + $in: [ + 'url', + ], + }, }, ], }); - - if (monitors && monitors.length) { - for (const monitor of monitors) { - if ( - monitor.pollTime.length === 0 || - !monitor.pollTime.some( - pt => String(pt.lighthouseId) === String(lighthouseId) - ) - ) { - await MonitorModel.updateOne( - { _id: monitor._id }, - { $push: { pollTime: { lighthouseId, date: newdate } } } - ); - } else { - await MonitorModel.updateOne( - { - _id: monitor._id, - pollTime: { - $elemMatch: { - lighthouseId, - }, - }, - }, - { $set: { 'pollTime.$.date': newdate } } - ); - } - } - return monitors; - } else { - return []; - } + return monitors; } catch (error) { ErrorService.log('monitorService.getUrlMonitors', error); throw error; @@ -1002,7 +956,7 @@ module.exports = { } }, - addSeat: async function(query) { + addSeat: async function (query) { try { const project = await ProjectService.findOneBy(query); let projectSeats = project.seats; @@ -1027,7 +981,7 @@ module.exports = { } }, - addSiteUrl: async function(query, data) { + addSiteUrl: async function (query, data) { try { let monitor = await this.findOneBy(query); @@ -1053,7 +1007,7 @@ module.exports = { } }, - removeSiteUrl: async function(query, data) { + removeSiteUrl: async function (query, data) { try { let monitor = await this.findOneBy(query); const siteUrlIndex = @@ -1082,7 +1036,7 @@ module.exports = { } }, - hardDeleteBy: async function(query) { + hardDeleteBy: async function (query) { try { await MonitorModel.deleteMany(query); return 'Monitor(s) removed successfully!'; @@ -1146,14 +1100,14 @@ module.exports = { status = incidents.some(inc => inc.resolvedAt ? moment(inc.resolvedAt) - .utc() - .startOf('day') - .diff( - moment(temp.date) - .utc() - .startOf('day'), - 'days' - ) > 0 + .utc() + .startOf('day') + .diff( + moment(temp.date) + .utc() + .startOf('day'), + 'days' + ) > 0 : true ) ? 'offline' @@ -1171,23 +1125,23 @@ module.exports = { ); const resolveddiff = inc.resolvedAt ? moment(temp.date) - .utc() - .startOf('day') - .diff( - moment(inc.resolvedAt) - .utc() - .startOf('day'), - 'days' - ) + .utc() + .startOf('day') + .diff( + moment(inc.resolvedAt) + .utc() + .startOf('day'), + 'days' + ) : moment(temp.date) - .utc() - .startOf('day') - .diff( - moment() - .utc() - .startOf('day'), - 'days' - ); + .utc() + .startOf('day') + .diff( + moment() + .utc() + .startOf('day'), + 'days' + ); if (creatediff > 0 && resolveddiff < 0) { return 1440; } else if (creatediff === 0 && resolveddiff !== 0) { @@ -1226,7 +1180,7 @@ module.exports = { } }, - restoreBy: async function(query) { + restoreBy: async function (query) { const _this = this; query.deleted = true; const monitor = await _this.findBy(query); @@ -1256,7 +1210,7 @@ module.exports = { // checks if the monitor uptime stat is within the defined uptime on monitor sla // then update the monitor => breachedMonitorSla - updateMonitorSlaStat: async function(query) { + updateMonitorSlaStat: async function (query) { try { const _this = this; const currentDate = moment().format(); @@ -1324,7 +1278,7 @@ module.exports = { } }, - calculateTime: async function(statuses, start, range) { + calculateTime: async function (statuses, start, range) { const timeBlock = []; let totalUptime = 0; let totalTime = 0; @@ -1391,8 +1345,8 @@ module.exports = { moment(a.start).isSame(b.start) ? 0 : moment(a.start).isAfter(b.start) - ? 1 - : -1 + ? 1 + : -1 ); //Third step for (let i = 0; i < incidentsHappenedDuringTheDay.length - 1; i++) { @@ -1528,7 +1482,7 @@ module.exports = { return { timeBlock, uptimePercent: (totalUptime / totalTime) * 100 }; }, - closeBreachedMonitorSla: async function(projectId, monitorId, userId) { + closeBreachedMonitorSla: async function (projectId, monitorId, userId) { try { const monitor = await MonitorModel.findOneAndUpdate( { @@ -1550,7 +1504,7 @@ module.exports = { } }, - changeMonitorComponent: async function(projectId, monitorId, componentId) { + changeMonitorComponent: async function (projectId, monitorId, componentId) { const monitor = await this.findOneBy({ _id: monitorId }); const component = await componentService.findOneBy({ _id: componentId, @@ -1574,7 +1528,7 @@ module.exports = { return updatedMonitor; }, - calcTime: async function(statuses, start, range) { + calcTime: async function (statuses, start, range) { const timeBlock = []; let totalUptime = 0; let totalTime = 0; @@ -1665,8 +1619,8 @@ module.exports = { moment(a.start).isSame(b.start) ? 0 : moment(a.start).isAfter(b.start) - ? 1 - : -1 + ? 1 + : -1 ); //Third step for (let i = 0; i < incidentsHappenedDuringTheDay.length - 1; i++) { diff --git a/dashboard/.env b/dashboard/.env index c26c818803..4c910fefeb 100644 --- a/dashboard/.env +++ b/dashboard/.env @@ -4,8 +4,8 @@ STRIPE_PUBLIC_KEY=pk_test_UynUDrFmbBmFVgJXd9EZCvBj00QAVpdwPv AMPLITUDE_PUBLIC_KEY=4b76c47248f969446af69dfdbf687d90 SKIP_PREFLIGHT_CHECK=true PUBLIC_URL=/dashboard -#REACT_APP_IS_SAAS_SERVICE=true -#IS_SAAS_SERVICE=true +REACT_APP_IS_SAAS_SERVICE=true +IS_SAAS_SERVICE=true REACT_APP_VERSION=$npm_package_version REACT_APP_PUSHNOTIFICATION_PUBLIC_KEY=BFAPbOTTU14VbTe_dnoYlVnOPLKUNm8GYmC50n3i4Ps64sk1Xqx8e894Clrscn1L2PsQ8-l4SsJVw7NRg4cx69Y STATUSPAGE_DOMAIN=staging-statuspage.fyipe.com \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 814cc46d03..8bbb6b9112 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -284,7 +284,7 @@ services: - /usr/src/app/node_modules/ lighthouse-runner: ports: - - '3001:3001' + - '3015:3015' - '9241:9229' # Debugging port. build: context: ./lighthouse-runner @@ -292,10 +292,8 @@ services: env_file: - ./lighthouse-runner/.env environment: - - PORT=3001 + - PORT=3015 - SERVER_URL=http://backend:3002 - - LIGHTHOUSE_NAME=US - - LIGHTHOUSE_KEY=test-key - IS_SAAS_SERVICE=${IS_SAAS_SERVICE} volumes: - ./lighthouse-runner:/usr/src/app diff --git a/docker-compose.yml b/docker-compose.yml index bfe42c1510..e7b1630fe3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -194,12 +194,12 @@ services: - backend lighthouse-runner: ports: - - '3001:3001' + - '3015:3015' build: ./lighthouse-runner env_file: - ./lighthouse-runner/.env environment: - - PORT=3001 + - PORT=3015 - SERVER_URL=http://backend:3002 - IS_SAAS_SERVICE=${IS_SAAS_SERVICE} depends_on: diff --git a/lighthouse-runner/.env b/lighthouse-runner/.env index acfe4a67d0..5f07e656d6 100644 --- a/lighthouse-runner/.env +++ b/lighthouse-runner/.env @@ -1,4 +1,2 @@ CLUSTER_KEY=f414c23b4cdf4e84a6a66ecfd528eff2 -LIGHTHOUSE_NAME=US -LIGHTHOUSE_KEY=33b674ca-9fdd-11e9-a2a3-2a2ae2dbccez SERVER_URL=http://localhost:3002 diff --git a/lighthouse-runner/Dockerfile b/lighthouse-runner/Dockerfile index a856d4e062..904587d4f2 100755 --- a/lighthouse-runner/Dockerfile +++ b/lighthouse-runner/Dockerfile @@ -29,8 +29,8 @@ RUN npm ci --only=production COPY . /usr/src/app # Expose ports. -# - 3001: Lighthouse Runner -EXPOSE 3001 +# - 3015: Lighthouse Runner +EXPOSE 3015 #Run the app CMD [ "npm", "start"] diff --git a/lighthouse-runner/Dockerfile.dev b/lighthouse-runner/Dockerfile.dev index d91f63136f..af8e6eb521 100644 --- a/lighthouse-runner/Dockerfile.dev +++ b/lighthouse-runner/Dockerfile.dev @@ -30,8 +30,8 @@ COPY ./package-lock.json /usr/src/app/package-lock.json RUN npm ci # Expose ports. -# - 3001: Lighthouse Runner -EXPOSE 3001 +# - 3015: Lighthouse Runner +EXPOSE 3015 #Run the app CMD [ "npm", "run", "dev"] diff --git a/lighthouse-runner/index.js b/lighthouse-runner/index.js index 98f4b66e05..f541a741d3 100644 --- a/lighthouse-runner/index.js +++ b/lighthouse-runner/index.js @@ -35,14 +35,12 @@ const config = require('./utils/config'); const cronMinuteStartTime = Math.floor(Math.random() * 50); app.use(cors()); -app.set('port', process.env.PORT || 3001); +app.set('port', process.env.PORT || 3015); http.listen(app.get('port'), function() { // eslint-disable-next-line console.log( - `Lighthouse with Lighthouse Name ${config.lighthouseName} and Lighthouse Key ${ - config.lighthouseKey - } Started on port ${app.get('port')}. Fyipe API URL: ${ + `Lighthouse Started on port ${app.get('port')}. Fyipe API URL: ${ config.serverUrl }` ); diff --git a/lighthouse-runner/utils/api.js b/lighthouse-runner/utils/api.js index 4dccbbd988..34f75b9807 100755 --- a/lighthouse-runner/utils/api.js +++ b/lighthouse-runner/utils/api.js @@ -7,10 +7,7 @@ const _this = { 'Access-Control-Allow-Origin': '*', Accept: 'application/json', 'Content-Type': 'application/json;charset=UTF-8', - lighthouseName: config.lighthouseName, - lighthouseKey: config.lighthouseKey, clusterKey: config.clusterKey, - lighthouseVersion: config.lighthouseVersion, }; }, postApi: (url, data) => { diff --git a/lighthouse-runner/utils/config.js b/lighthouse-runner/utils/config.js index eff9a6940e..987c9720a2 100644 --- a/lighthouse-runner/utils/config.js +++ b/lighthouse-runner/utils/config.js @@ -39,8 +39,6 @@ const COMMAND = { module.exports = { COMMAND, serverUrl: process.env['SERVER_URL'], - lighthouseName: process.env['LIGHTHOUSE_NAME'], - lighthouseKey: process.env['LIGHTHOUSE_KEY'], clusterKey: process.env['CLUSTER_KEY'], lighthouseVersion: packageJson.version, }; diff --git a/lighthouse-runner/workers/main.js b/lighthouse-runner/workers/main.js index 69a08f8324..1ff2db7e94 100644 --- a/lighthouse-runner/workers/main.js +++ b/lighthouse-runner/workers/main.js @@ -9,9 +9,11 @@ module.exports = { monitors = JSON.parse(monitors.data); // parse the stringified data await Promise.all( monitors.map(monitor => { + // console.log("The received monitor: ", monitor); if(monitor.type === 'url' && monitor.pollTime && monitor.pollTime.length > 0){ const probe = monitor.pollTime.filter(probe => probe.probeId); if(probe.length > 0){ // This checks that the probe server is working + console.log("The received monitor after probe check: ", monitor); return UrlMonitors.ping(monitor); }else{ ErrorService.log('getApi',"Please Make Sure Probe Server is Online.") diff --git a/lighthouse-runner/workers/urlMonitors.js b/lighthouse-runner/workers/urlMonitors.js index 4cc6910435..b173307b2a 100755 --- a/lighthouse-runner/workers/urlMonitors.js +++ b/lighthouse-runner/workers/urlMonitors.js @@ -48,11 +48,12 @@ module.exports = { let failedCount = 0; for (const url of sites) { try { - const resp = await lighthouseFetch( + let resp = await lighthouseFetch( monitor, url ); - + resp.lighthouseScanStatus = resp.status + console.log("Response from lighthouse fetch: ", resp); await UrlService.ping(monitor._id, { monitor, resp, @@ -66,15 +67,6 @@ module.exports = { } } - await UrlService.ping(monitor._id, { - monitor, - resp: { - lighthouseScanStatus: - failedCount === sites.length - ? 'failed' - : 'scanned', - }, - }); } } } diff --git a/probe/workers/urlMonitors.js b/probe/workers/urlMonitors.js index 6164793672..80bfb8d1f2 100755 --- a/probe/workers/urlMonitors.js +++ b/probe/workers/urlMonitors.js @@ -42,7 +42,6 @@ module.exports = { retryCount++; } } - // Lighthouse Refactored } } } catch (error) { From fcbad6a70f8b3c80998da21b0b6c0779b212493d Mon Sep 17 00:00:00 2001 From: David Adewole Date: Thu, 1 Jul 2021 14:34:44 +0100 Subject: [PATCH 13/22] lighthouse-runner --- backend/backend/services/monitorService.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/backend/services/monitorService.js b/backend/backend/services/monitorService.js index e3d2e4b531..f35b68e70f 100755 --- a/backend/backend/services/monitorService.js +++ b/backend/backend/services/monitorService.js @@ -707,13 +707,13 @@ module.exports = { $or: [ { lighthouseScanStatus: { - $exists: false, + $exists: false, // Lighthouse scan status does not exist } }, { lighthouseScanStatus: { $exists: true, - $nin: ['scanning', 'scanned'] + $nin: ['scanning', 'scanned'] // Lighthouse scan status exist but 'failed' } } ] From 04fc0b439de38aadc14846d1c9141318a40afffc Mon Sep 17 00:00:00 2001 From: David Adewole Date: Thu, 1 Jul 2021 14:35:28 +0100 Subject: [PATCH 14/22] lighthouse-runner --- backend/backend/services/monitorService.js | 172 +++++++++++++-------- 1 file changed, 109 insertions(+), 63 deletions(-) diff --git a/backend/backend/services/monitorService.js b/backend/backend/services/monitorService.js index f35b68e70f..81d86b6129 100755 --- a/backend/backend/services/monitorService.js +++ b/backend/backend/services/monitorService.js @@ -5,7 +5,7 @@ module.exports = { //Params: //Param 1: data: MonitorModal. //Returns: promise with monitor model or error. - create: async function (data) { + create: async function(data) { try { const _this = this; let subProject = null; @@ -74,8 +74,8 @@ module.exports = { plan.category === 'Startup' ? 5 : plan.category === 'Growth' - ? 10 - : 0; + ? 10 + : 0; if ( count < userCount * monitorCount || !IS_SAAS_SERVICE || @@ -178,7 +178,7 @@ module.exports = { } }, - updateOneBy: async function (query, data, unsetData) { + updateOneBy: async function(query, data, unsetData) { const _this = this; try { @@ -254,7 +254,7 @@ module.exports = { } }, - updateBy: async function (query, data) { + updateBy: async function(query, data) { try { if (!query) { query = {}; @@ -354,7 +354,7 @@ module.exports = { } }, - deleteBy: async function (query, userId) { + deleteBy: async function(query, userId) { try { if (!query) { query = {}; @@ -695,8 +695,9 @@ module.exports = { } }, - async getUrlMonitors() { + async getUrlMonitors(lighthouseId, date) { try { + const newdate = new Date(); const monitors = await MonitorModel.find({ $and: [ { @@ -706,28 +707,73 @@ module.exports = { { $or: [ { - lighthouseScanStatus: { - $exists: false, // Lighthouse scan status does not exist - } + $and: [ + { + type: { + $in: [ + 'url', + ], + }, + }, + { + $or: [ + { + pollTime: { + $elemMatch: { + lighthouseId, + date: { $lt: date }, + }, + }, + }, + { + //pollTime doesn't include the probeId yet. + pollTime: { + $not: { + $elemMatch: { + lighthouseId, + }, + }, + }, + }, + ], + }, + ], }, - { - lighthouseScanStatus: { - $exists: true, - $nin: ['scanning', 'scanned'] // Lighthouse scan status exist but 'failed' - } - } - ] - }, - { - type: { - $in: [ - 'url', - ], - }, + ], }, ], }); - return monitors; + + if (monitors && monitors.length) { + for (const monitor of monitors) { + if ( + monitor.pollTime.length === 0 || + !monitor.pollTime.some( + pt => String(pt.lighthouseId) === String(lighthouseId) + ) + ) { + await MonitorModel.updateOne( + { _id: monitor._id }, + { $push: { pollTime: { lighthouseId, date: newdate } } } + ); + } else { + await MonitorModel.updateOne( + { + _id: monitor._id, + pollTime: { + $elemMatch: { + lighthouseId, + }, + }, + }, + { $set: { 'pollTime.$.date': newdate } } + ); + } + } + return monitors; + } else { + return []; + } } catch (error) { ErrorService.log('monitorService.getUrlMonitors', error); throw error; @@ -956,7 +1002,7 @@ module.exports = { } }, - addSeat: async function (query) { + addSeat: async function(query) { try { const project = await ProjectService.findOneBy(query); let projectSeats = project.seats; @@ -981,7 +1027,7 @@ module.exports = { } }, - addSiteUrl: async function (query, data) { + addSiteUrl: async function(query, data) { try { let monitor = await this.findOneBy(query); @@ -1007,7 +1053,7 @@ module.exports = { } }, - removeSiteUrl: async function (query, data) { + removeSiteUrl: async function(query, data) { try { let monitor = await this.findOneBy(query); const siteUrlIndex = @@ -1036,7 +1082,7 @@ module.exports = { } }, - hardDeleteBy: async function (query) { + hardDeleteBy: async function(query) { try { await MonitorModel.deleteMany(query); return 'Monitor(s) removed successfully!'; @@ -1100,14 +1146,14 @@ module.exports = { status = incidents.some(inc => inc.resolvedAt ? moment(inc.resolvedAt) - .utc() - .startOf('day') - .diff( - moment(temp.date) - .utc() - .startOf('day'), - 'days' - ) > 0 + .utc() + .startOf('day') + .diff( + moment(temp.date) + .utc() + .startOf('day'), + 'days' + ) > 0 : true ) ? 'offline' @@ -1125,23 +1171,23 @@ module.exports = { ); const resolveddiff = inc.resolvedAt ? moment(temp.date) - .utc() - .startOf('day') - .diff( - moment(inc.resolvedAt) - .utc() - .startOf('day'), - 'days' - ) + .utc() + .startOf('day') + .diff( + moment(inc.resolvedAt) + .utc() + .startOf('day'), + 'days' + ) : moment(temp.date) - .utc() - .startOf('day') - .diff( - moment() - .utc() - .startOf('day'), - 'days' - ); + .utc() + .startOf('day') + .diff( + moment() + .utc() + .startOf('day'), + 'days' + ); if (creatediff > 0 && resolveddiff < 0) { return 1440; } else if (creatediff === 0 && resolveddiff !== 0) { @@ -1180,7 +1226,7 @@ module.exports = { } }, - restoreBy: async function (query) { + restoreBy: async function(query) { const _this = this; query.deleted = true; const monitor = await _this.findBy(query); @@ -1210,7 +1256,7 @@ module.exports = { // checks if the monitor uptime stat is within the defined uptime on monitor sla // then update the monitor => breachedMonitorSla - updateMonitorSlaStat: async function (query) { + updateMonitorSlaStat: async function(query) { try { const _this = this; const currentDate = moment().format(); @@ -1278,7 +1324,7 @@ module.exports = { } }, - calculateTime: async function (statuses, start, range) { + calculateTime: async function(statuses, start, range) { const timeBlock = []; let totalUptime = 0; let totalTime = 0; @@ -1345,8 +1391,8 @@ module.exports = { moment(a.start).isSame(b.start) ? 0 : moment(a.start).isAfter(b.start) - ? 1 - : -1 + ? 1 + : -1 ); //Third step for (let i = 0; i < incidentsHappenedDuringTheDay.length - 1; i++) { @@ -1482,7 +1528,7 @@ module.exports = { return { timeBlock, uptimePercent: (totalUptime / totalTime) * 100 }; }, - closeBreachedMonitorSla: async function (projectId, monitorId, userId) { + closeBreachedMonitorSla: async function(projectId, monitorId, userId) { try { const monitor = await MonitorModel.findOneAndUpdate( { @@ -1504,7 +1550,7 @@ module.exports = { } }, - changeMonitorComponent: async function (projectId, monitorId, componentId) { + changeMonitorComponent: async function(projectId, monitorId, componentId) { const monitor = await this.findOneBy({ _id: monitorId }); const component = await componentService.findOneBy({ _id: componentId, @@ -1528,7 +1574,7 @@ module.exports = { return updatedMonitor; }, - calcTime: async function (statuses, start, range) { + calcTime: async function(statuses, start, range) { const timeBlock = []; let totalUptime = 0; let totalTime = 0; @@ -1619,8 +1665,8 @@ module.exports = { moment(a.start).isSame(b.start) ? 0 : moment(a.start).isAfter(b.start) - ? 1 - : -1 + ? 1 + : -1 ); //Third step for (let i = 0; i < incidentsHappenedDuringTheDay.length - 1; i++) { From c996e42af6f357840046e6035ec5ae530ac24bbe Mon Sep 17 00:00:00 2001 From: David Adewole Date: Thu, 1 Jul 2021 14:36:37 +0100 Subject: [PATCH 15/22] lighthouse-runner --- backend/backend/services/monitorService.js | 84 +++++----------------- 1 file changed, 19 insertions(+), 65 deletions(-) diff --git a/backend/backend/services/monitorService.js b/backend/backend/services/monitorService.js index 81d86b6129..41fb43d789 100755 --- a/backend/backend/services/monitorService.js +++ b/backend/backend/services/monitorService.js @@ -695,9 +695,8 @@ module.exports = { } }, - async getUrlMonitors(lighthouseId, date) { + async getUrlMonitors() { try { - const newdate = new Date(); const monitors = await MonitorModel.find({ $and: [ { @@ -707,73 +706,28 @@ module.exports = { { $or: [ { - $and: [ - { - type: { - $in: [ - 'url', - ], - }, - }, - { - $or: [ - { - pollTime: { - $elemMatch: { - lighthouseId, - date: { $lt: date }, - }, - }, - }, - { - //pollTime doesn't include the probeId yet. - pollTime: { - $not: { - $elemMatch: { - lighthouseId, - }, - }, - }, - }, - ], - }, - ], + lighthouseScanStatus: { + $exists: false, // Lighthouse scan status does not exist + } }, - ], + { + lighthouseScanStatus: { + $exists: true, + $nin: ['scanning', 'scanned'] // Lighthouse scan status exist but 'failed' + } + } + ] + }, + { + type: { + $in: [ + 'url', + ], + }, }, ], }); - - if (monitors && monitors.length) { - for (const monitor of monitors) { - if ( - monitor.pollTime.length === 0 || - !monitor.pollTime.some( - pt => String(pt.lighthouseId) === String(lighthouseId) - ) - ) { - await MonitorModel.updateOne( - { _id: monitor._id }, - { $push: { pollTime: { lighthouseId, date: newdate } } } - ); - } else { - await MonitorModel.updateOne( - { - _id: monitor._id, - pollTime: { - $elemMatch: { - lighthouseId, - }, - }, - }, - { $set: { 'pollTime.$.date': newdate } } - ); - } - } - return monitors; - } else { - return []; - } + return monitors; } catch (error) { ErrorService.log('monitorService.getUrlMonitors', error); throw error; From 9cfca25391de37dff7757d4f42ad04c9ed079c08 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Thu, 1 Jul 2021 14:54:13 +0100 Subject: [PATCH 16/22] lighthouse-runner --- lighthouse-runner/workers/urlMonitors.js | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/lighthouse-runner/workers/urlMonitors.js b/lighthouse-runner/workers/urlMonitors.js index b173307b2a..aafdad9720 100755 --- a/lighthouse-runner/workers/urlMonitors.js +++ b/lighthouse-runner/workers/urlMonitors.js @@ -1,20 +1,11 @@ /* eslint-disable no-console */ const UrlService = require('../utils/urlService'); const ErrorService = require('../utils/errorService'); -const fetch = require('node-fetch'); -const sslCert = require('get-ssl-certificate'); const { fork } = require('child_process'); const moment = require('moment'); -const https = require('https'); -const http = require('http'); -const httpsAgent = new https.Agent({ - rejectUnauthorized: false, -}); -const httpAgent = new http.Agent(); -// it collects all monitors then ping them one by one to store their response -// checks if the website of the url in the monitors is up or down -// creates incident if a website is down and resolves it when they come back up + +// This runs the lighthouse of URL Monitors module.exports = { ping: async monitor => { @@ -48,11 +39,11 @@ module.exports = { let failedCount = 0; for (const url of sites) { try { - let resp = await lighthouseFetch( + const resp = await lighthouseFetch( monitor, url ); - resp.lighthouseScanStatus = resp.status + console.log("Response from lighthouse fetch: ", resp); await UrlService.ping(monitor._id, { monitor, @@ -96,9 +87,9 @@ const lighthouseFetch = (monitor, url) => { clearTimeout(timeoutHandler); lighthouseWorker.removeAllListeners(); if (result.error) { - reject({ status: 'failed', ...result }); + reject({ lighthouseScanStatus: 'failed', ...result }); } else { - resolve({ status: 'scanned', ...result }); + resolve({ lighthouseScanStatus: 'scanned', ...result }); } } }); From 585645a0df0a9ffa38af2d53cfc42f5c27ff0b7f Mon Sep 17 00:00:00 2001 From: David Adewole Date: Thu, 1 Jul 2021 16:37:38 +0100 Subject: [PATCH 17/22] lighthouse-runner --- backend/backend/api/lighthouse.js | 4 ++-- lighthouse-runner/workers/main.js | 6 ++---- lighthouse-runner/workers/urlMonitors.js | 1 - 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/backend/backend/api/lighthouse.js b/backend/backend/api/lighthouse.js index 7603b66957..59eafa7fc5 100644 --- a/backend/backend/api/lighthouse.js +++ b/backend/backend/api/lighthouse.js @@ -45,7 +45,7 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( monitor, resp, } = req.body; - console.log("Lighthouse Ping body: ", req.body); + let log, data = {}; data = req.body; @@ -66,7 +66,7 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( data.monitorId = req.params.monitorId || monitor._id; let probeId = await ProbeService.findBy(); data.probeId = probeId ? probeId[0]._id : null; - + if (data.lighthouseScanStatus === 'scanning') { await MonitorService.updateOneBy( { _id: data.monitorId }, diff --git a/lighthouse-runner/workers/main.js b/lighthouse-runner/workers/main.js index 1ff2db7e94..fde1ab9114 100644 --- a/lighthouse-runner/workers/main.js +++ b/lighthouse-runner/workers/main.js @@ -9,11 +9,9 @@ module.exports = { monitors = JSON.parse(monitors.data); // parse the stringified data await Promise.all( monitors.map(monitor => { - // console.log("The received monitor: ", monitor); - if(monitor.type === 'url' && monitor.pollTime && monitor.pollTime.length > 0){ + if(monitor.type === 'url'){ const probe = monitor.pollTime.filter(probe => probe.probeId); - if(probe.length > 0){ // This checks that the probe server is working - console.log("The received monitor after probe check: ", monitor); + if(probe.length > 0){ // This checks that the ssl result has already been published i.e probe is runnning. return UrlMonitors.ping(monitor); }else{ ErrorService.log('getApi',"Please Make Sure Probe Server is Online.") diff --git a/lighthouse-runner/workers/urlMonitors.js b/lighthouse-runner/workers/urlMonitors.js index aafdad9720..8ed6b01b85 100755 --- a/lighthouse-runner/workers/urlMonitors.js +++ b/lighthouse-runner/workers/urlMonitors.js @@ -44,7 +44,6 @@ module.exports = { url ); - console.log("Response from lighthouse fetch: ", resp); await UrlService.ping(monitor._id, { monitor, resp, From 2f02df1490c016e666384caacef533c42e7cff45 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Thu, 1 Jul 2021 16:38:26 +0100 Subject: [PATCH 18/22] lighthouse-runner --- accounts/.env | 4 ++-- backend/.env | 4 ++-- dashboard/.env | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accounts/.env b/accounts/.env index 039551cc8b..4fe4557e50 100644 --- a/accounts/.env +++ b/accounts/.env @@ -4,6 +4,6 @@ STRIPE_PUBLIC_KEY=pk_test_UynUDrFmbBmFVgJXd9EZCvBj00QAVpdwPv AMPLITUDE_PUBLIC_KEY=cb70632f45c1ca7fe6180812c0d6494a SKIP_PREFLIGHT_CHECK=true PUBLIC_URL=/accounts -REACT_APP_IS_SAAS_SERVICE=true -IS_SAAS_SERVICE=true +#REACT_APP_IS_SAAS_SERVICE=true +#IS_SAAS_SERVICE=true #REACT_APP_DISABLE_SIGNUP=true diff --git a/backend/.env b/backend/.env index 33552de80e..c271bacb24 100755 --- a/backend/.env +++ b/backend/.env @@ -10,9 +10,9 @@ MONGO_URL=mongodb://localhost:27017/fyipedb REDIS_HOST=localhost CLUSTER_KEY=f414c23b4cdf4e84a6a66ecfd528eff2 TEST_TWILIO_NUMBER=+919910568840 -IS_SAAS_SERVICE=true +#IS_SAAS_SERVICE=true ENCRYPTION_KEY=01234567890123456789012345678901 -IS_TESTING=true +#IS_TESTING=true PUSHNOTIFICATION_PRIVATE_KEY=8aXTsH48-cegK-xBApLxxOezCOZIjaWpg81Dny2zbio PUSHNOTIFICATION_PUBLIC_KEY=BFAPbOTTU14VbTe_dnoYlVnOPLKUNm8GYmC50n3i4Ps64sk1Xqx8e894Clrscn1L2PsQ8-l4SsJVw7NRg4cx69Y PUSHNOTIFICATION_URL=mailto:support@fyipe.com diff --git a/dashboard/.env b/dashboard/.env index 4c910fefeb..c26c818803 100644 --- a/dashboard/.env +++ b/dashboard/.env @@ -4,8 +4,8 @@ STRIPE_PUBLIC_KEY=pk_test_UynUDrFmbBmFVgJXd9EZCvBj00QAVpdwPv AMPLITUDE_PUBLIC_KEY=4b76c47248f969446af69dfdbf687d90 SKIP_PREFLIGHT_CHECK=true PUBLIC_URL=/dashboard -REACT_APP_IS_SAAS_SERVICE=true -IS_SAAS_SERVICE=true +#REACT_APP_IS_SAAS_SERVICE=true +#IS_SAAS_SERVICE=true REACT_APP_VERSION=$npm_package_version REACT_APP_PUSHNOTIFICATION_PUBLIC_KEY=BFAPbOTTU14VbTe_dnoYlVnOPLKUNm8GYmC50n3i4Ps64sk1Xqx8e894Clrscn1L2PsQ8-l4SsJVw7NRg4cx69Y STATUSPAGE_DOMAIN=staging-statuspage.fyipe.com \ No newline at end of file From eb26d06b88e8ae192867a7ec04f15bd98959d4b8 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Thu, 1 Jul 2021 16:52:48 +0100 Subject: [PATCH 19/22] lighthouse-runner --- backend/backend/api/lighthouse.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/backend/api/lighthouse.js b/backend/backend/api/lighthouse.js index 59eafa7fc5..6a5fa24670 100644 --- a/backend/backend/api/lighthouse.js +++ b/backend/backend/api/lighthouse.js @@ -45,7 +45,7 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( monitor, resp, } = req.body; - + let log, data = {}; data = req.body; @@ -89,7 +89,7 @@ router.post('/ping/:monitorId', isAuthorizedLighthouse, async function ( lighthouseScannedBy: data.probeId, } ); - if (data.lighthouseData) { // The scanned result are published + if (data.lighthouseData) { // The scanned results are published data.scanning = false; log = await ProbeService.saveLighthouseLog(data); } From 19ea59c2eecef6ecb915aba59b70418255b34ee7 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Thu, 1 Jul 2021 17:12:17 +0100 Subject: [PATCH 20/22] lighthouse-runner --- backend/backend/services/monitorService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/backend/services/monitorService.js b/backend/backend/services/monitorService.js index 41fb43d789..9ff41096b4 100755 --- a/backend/backend/services/monitorService.js +++ b/backend/backend/services/monitorService.js @@ -713,7 +713,7 @@ module.exports = { { lighthouseScanStatus: { $exists: true, - $nin: ['scanning', 'scanned'] // Lighthouse scan status exist but 'failed' + $nin: ['scanning', 'scanned'] // Lighthouse scan status exist but 'failed' or the 'scan' button is clicked from UI } } ] From 745c23175c649dbb942239673e8db28a8ac94fd2 Mon Sep 17 00:00:00 2001 From: David Adewole Date: Fri, 2 Jul 2021 10:34:25 +0100 Subject: [PATCH 21/22] lighthouse-runner --- backend/backend/services/monitorService.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/backend/services/monitorService.js b/backend/backend/services/monitorService.js index 9ff41096b4..f15fcc4bee 100755 --- a/backend/backend/services/monitorService.js +++ b/backend/backend/services/monitorService.js @@ -697,6 +697,9 @@ module.exports = { async getUrlMonitors() { try { + const oneDay = moment() + .subtract(1, 'days') + .toDate(); const monitors = await MonitorModel.find({ $and: [ { @@ -715,7 +718,8 @@ module.exports = { $exists: true, $nin: ['scanning', 'scanned'] // Lighthouse scan status exist but 'failed' or the 'scan' button is clicked from UI } - } + }, + { lighthouseScannedAt: { $lt: oneDay } } ] }, { From ec03140c254b63cc9faab583212c908d02e7dcf1 Mon Sep 17 00:00:00 2001 From: Nawaz Dhandala Date: Tue, 6 Jul 2021 08:34:19 +0000 Subject: [PATCH 22/22] Update index.js --- lighthouse-runner/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lighthouse-runner/index.js b/lighthouse-runner/index.js index f541a741d3..47a42142fe 100644 --- a/lighthouse-runner/index.js +++ b/lighthouse-runner/index.js @@ -63,11 +63,11 @@ app.get(['/lighthouse/version', '/version'], function(req, res) { res.send({ lighthouseVersion: process.env.npm_package_version }); }); -// This cron runs every other minute. -cron.schedule('*/2 * * * *', () => { +// This cron runs every 10 minute. +cron.schedule('*/10 * * * *', () => { setTimeout(() => { Main.runJob(); }, cronMinuteStartTime * 1000); }); -module.exports = app; \ No newline at end of file +module.exports = app;