From 0bda0984baecc335f9ceca5478ea6b110b31e46b Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Thu, 23 May 2019 16:11:33 -0400 Subject: [PATCH 01/24] Fix lock --- index.js | 1 + package.json | 3 ++- redis/index.js | 57 +++++++++++++++++++++++++++++++++++++++++++++++++- services/db.js | 3 +++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 9024587..a0240e2 100644 --- a/index.js +++ b/index.js @@ -6,6 +6,7 @@ module.exports.setup = require('./services/setup'); module.exports.put = db.put; module.exports.get = db.get; module.exports.del = db.del; +module.exports.applyLock = db.applyLock; module.exports.batch = db.batch; module.exports.putMeta = db.putMeta; module.exports.patchMeta = db.patchMeta; diff --git a/package.json b/package.json index 7847d29..4e0c784 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "knex": "^0.15.2", "pg": "7.4.3", "pg-query-stream": "^1.1.1", - "postgres-migrations": "^3.0.2" + "postgres-migrations": "^3.0.2", + "redlock": "^3.1.2" }, "devDependencies": { "coveralls": "^3.0.1", diff --git a/redis/index.js b/redis/index.js index c5f84a8..3f7b12a 100644 --- a/redis/index.js +++ b/redis/index.js @@ -4,7 +4,9 @@ const bluebird = require('bluebird'), Redis = require('ioredis'), { REDIS_URL, REDIS_HASH } = require('../services/constants'), { isPublished, isUri, isUser } = require('clayutils'), - { notFoundError, logGenericError } = require('../services/errors'); + { notFoundError, logGenericError } = require('../services/errors'), + Redlock = require('redlock'); + var log = require('../services/log').setup({ file: __filename }); /** @@ -26,10 +28,61 @@ function createClient(testRedisUrl) { module.exports.client = bluebird.promisifyAll(new Redis(redisUrl)); module.exports.client.on('error', logGenericError(__filename)); + // TODO: Move this config to another module maybe? + const redlock = new Redlock([module.exports.client], { + // the expected clock drift; for more details + // see http://redis.io/topics/distlock + driftFactor: 0.01, // time in ms + + // the max number of times Redlock will attempt + // to lock a resource before erroring + retryCount: 0, + + // the time in ms between attempts + retryDelay: 200, // time in ms + + // the max time in ms randomly added to retries + // to improve performance under high contention + // see https://www.awsarchitectureblog.com/2015/03/backoff.html + retryJitter: 200 // time in ms + }); + + redlock.on('clientError', logGenericError(__filename)); + module.exports.redlock = redlock; + resolve({ server: redisUrl }); }); } +function lockRedisForAction(resourceId) { + console.log('lockRedisForAction', { resourceId, lock: module.exports.redlock.lock }); + return module.exports.redlock.lock(resourceId, 1200); +} + +function unlockWhenReady(lock, cb) { + return cb() + .then(result => module.exports.redlock.unlock(lock).then(() => result)); +} +function getFromState(id) { + return module.exports.client.getAsync(id); +} + +function setInState(action) { + return module.exports.client.setAsync(action, true); +} + +function applyLock(resourceId, cb) { + const ACTION = 'bootstrap3'; + + return getFromState(ACTION).then(didRunBootstrap => { + if (didRunBootstrap) return; + + return setInState(ACTION) + .then(() => lockRedisForAction(resourceId)) + .then(lock => unlockWhenReady(lock, cb)); + }); +} + /** * Determines if we should write to cache * @@ -108,6 +161,8 @@ function del(key) { } module.exports.client = null; +module.exports.redlock; +module.exports.applyLock = applyLock; module.exports.createClient = createClient; module.exports.get = get; module.exports.put = put; diff --git a/services/db.js b/services/db.js index 3ff87ef..cf501f1 100644 --- a/services/db.js +++ b/services/db.js @@ -85,6 +85,9 @@ module.exports.put = put; module.exports.get = get; module.exports.del = del; module.exports.batch = batch; + +module.exports.applyLock = redis.applyLock; + module.exports.raw = postgres.raw; module.exports.putMeta = postgres.putMeta; module.exports.getMeta = postgres.getMeta; From f2675edde94aa25a020a0255621279dfa4c4fdd8 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Fri, 24 May 2019 16:39:01 -0400 Subject: [PATCH 02/24] Add states for the lock --- redis/index.js | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/redis/index.js b/redis/index.js index 3f7b12a..d225a3f 100644 --- a/redis/index.js +++ b/redis/index.js @@ -63,23 +63,49 @@ function unlockWhenReady(lock, cb) { return cb() .then(result => module.exports.redlock.unlock(lock).then(() => result)); } + function getFromState(id) { return module.exports.client.getAsync(id); } -function setInState(action) { - return module.exports.client.setAsync(action, true); +function setState(action, state) { + return module.exports.client.setAsync(action, state); +} + +function sleepAndRun(cb, ms = 1000) { + return new Promise(resolve => { + console.log('\n\nRUNNING THE FUNC AGAIN'); + setTimeout(() => { + cb().then(resolve); + }, ms); + }); } -function applyLock(resourceId, cb) { - const ACTION = 'bootstrap3'; +function applyLock(action, cb) { + const resourceId = action + '-lock'; - return getFromState(ACTION).then(didRunBootstrap => { - if (didRunBootstrap) return; + console.log({ resourceId, action }); - return setInState(ACTION) + return getFromState(action).then(state => { + console.log('\n\nSTATE', { state }); + /** + * If its ONGOING, just re-run this func after a while + * to see if the state changed + */ + if (state === 'ONGOING') { + return sleepAndRun(() => applyLock(action, cb), 500); + } + + if (state === 'FINISHED') return Promise.resolve(); + + if (!state || state === 'RETRY') return setState(action, 'ONGOING') .then(() => lockRedisForAction(resourceId)) - .then(lock => unlockWhenReady(lock, cb)); + .then(lock => unlockWhenReady(lock, cb)) + .then(() => setState(action, 'FINISHED')) + .catch(() => setState(action, 'RETRY')); + + console.log('\n\nThe state had a value that I didnt recognize', { state }); + return Promise.resolve(); }); } From d8b055ab1c45f977aeb4f3f36336a9dc5f1489bf Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Mon, 27 May 2019 15:51:47 -0400 Subject: [PATCH 03/24] Add TTL for status in redis --- redis/index.js | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/redis/index.js b/redis/index.js index d225a3f..315dc4b 100644 --- a/redis/index.js +++ b/redis/index.js @@ -54,9 +54,8 @@ function createClient(testRedisUrl) { }); } -function lockRedisForAction(resourceId) { - console.log('lockRedisForAction', { resourceId, lock: module.exports.redlock.lock }); - return module.exports.redlock.lock(resourceId, 1200); +function lockRedisForAction(resourceId, ttl) { + return module.exports.redlock.lock(resourceId, ttl); } function unlockWhenReady(lock, cb) { @@ -68,43 +67,40 @@ function getFromState(id) { return module.exports.client.getAsync(id); } -function setState(action, state) { - return module.exports.client.setAsync(action, state); +function setState(action, state, expire) { + return module.exports.client.setAsync(action, state) + .then(() => { + if (expire) return module.exports.client.expire(action, expire); // Expire in 10 minutes + }); } function sleepAndRun(cb, ms = 1000) { - return new Promise(resolve => { - console.log('\n\nRUNNING THE FUNC AGAIN'); - setTimeout(() => { - cb().then(resolve); - }, ms); - }); + return new Promise(resolve => setTimeout(() => cb().then(resolve), ms)); } function applyLock(action, cb) { - const resourceId = action + '-lock'; - - console.log({ resourceId, action }); + const resourceId = action + '-lock', + RETRY_TIME = 1500, // ms + KEY_TTL = 10 * 60, // secs + LOCK_TTL = 1200; return getFromState(action).then(state => { - console.log('\n\nSTATE', { state }); /** * If its ONGOING, just re-run this func after a while * to see if the state changed */ if (state === 'ONGOING') { - return sleepAndRun(() => applyLock(action, cb), 500); + return sleepAndRun(() => applyLock(action, cb), RETRY_TIME); } if (state === 'FINISHED') return Promise.resolve(); if (!state || state === 'RETRY') return setState(action, 'ONGOING') - .then(() => lockRedisForAction(resourceId)) + .then(() => lockRedisForAction(resourceId, LOCK_TTL)) .then(lock => unlockWhenReady(lock, cb)) - .then(() => setState(action, 'FINISHED')) + .then(() => setState(action, 'FINISHED', KEY_TTL)) .catch(() => setState(action, 'RETRY')); - console.log('\n\nThe state had a value that I didnt recognize', { state }); return Promise.resolve(); }); } From e22aba5a081a675099ceaa372aedd16f3cb35682 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Mon, 27 May 2019 16:27:04 -0400 Subject: [PATCH 04/24] Add logs, simplify some logic --- redis/index.js | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/redis/index.js b/redis/index.js index 315dc4b..35d853f 100644 --- a/redis/index.js +++ b/redis/index.js @@ -55,12 +55,17 @@ function createClient(testRedisUrl) { } function lockRedisForAction(resourceId, ttl) { + log('warn', `Trying to lock redis for resource id ${resourceId}`, { resourceId, processId: process.pid }); return module.exports.redlock.lock(resourceId, ttl); } -function unlockWhenReady(lock, cb) { +function unlockWhenReady(lock, resourceId, cb) { return cb() - .then(result => module.exports.redlock.unlock(lock).then(() => result)); + .then(result => module.exports.redlock.unlock(lock) + .then(() => { + log('warn', `Releasing lock for resource id ${resourceId}`, { resourceId, processId: process.pid }); + return result; + })); } function getFromState(id) { @@ -79,29 +84,30 @@ function sleepAndRun(cb, ms = 1000) { } function applyLock(action, cb) { - const resourceId = action + '-lock', + const resourceId = `${action}-lock`, + ACTIONS = { + ONGOING: 'ON-GOING', + RETRY: 'RETRY', + FINISHED: 'FINISHED' + }, RETRY_TIME = 1500, // ms KEY_TTL = 10 * 60, // secs - LOCK_TTL = 1200; + LOCK_TTL = 5000; // ms return getFromState(action).then(state => { /** - * If its ONGOING, just re-run this func after a while - * to see if the state changed + * If its ONGOING, just re-run this function after a while + * to see if the state changed. */ - if (state === 'ONGOING') { + if (state === ACTIONS.ONGOING) { return sleepAndRun(() => applyLock(action, cb), RETRY_TIME); } - if (state === 'FINISHED') return Promise.resolve(); - - if (!state || state === 'RETRY') return setState(action, 'ONGOING') + if (!state || state === 'RETRY') return setState(action, ACTIONS.ONGOING) .then(() => lockRedisForAction(resourceId, LOCK_TTL)) - .then(lock => unlockWhenReady(lock, cb)) - .then(() => setState(action, 'FINISHED', KEY_TTL)) - .catch(() => setState(action, 'RETRY')); - - return Promise.resolve(); + .then(lock => unlockWhenReady(lock, resourceId, cb)) + .then(() => setState(action, ACTIONS.FINISHED, KEY_TTL)) + .catch(() => setState(action, ACTIONS.RETRY)); }); } From ad096b75bf25eca1e46aba1cbf0e00b60c006eb0 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Mon, 27 May 2019 17:34:28 -0400 Subject: [PATCH 05/24] Move logic to a lock module --- redis/index.js | 84 ++---------------------------------- redis/lock.js | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ services/db.js | 2 - 3 files changed, 118 insertions(+), 83 deletions(-) create mode 100644 redis/lock.js diff --git a/redis/index.js b/redis/index.js index 35d853f..ac6918d 100644 --- a/redis/index.js +++ b/redis/index.js @@ -5,7 +5,7 @@ const bluebird = require('bluebird'), { REDIS_URL, REDIS_HASH } = require('../services/constants'), { isPublished, isUri, isUser } = require('clayutils'), { notFoundError, logGenericError } = require('../services/errors'), - Redlock = require('redlock'); + lock = require('./lock'); var log = require('../services/log').setup({ file: __filename }); @@ -28,89 +28,12 @@ function createClient(testRedisUrl) { module.exports.client = bluebird.promisifyAll(new Redis(redisUrl)); module.exports.client.on('error', logGenericError(__filename)); - // TODO: Move this config to another module maybe? - const redlock = new Redlock([module.exports.client], { - // the expected clock drift; for more details - // see http://redis.io/topics/distlock - driftFactor: 0.01, // time in ms - - // the max number of times Redlock will attempt - // to lock a resource before erroring - retryCount: 0, - - // the time in ms between attempts - retryDelay: 200, // time in ms - - // the max time in ms randomly added to retries - // to improve performance under high contention - // see https://www.awsarchitectureblog.com/2015/03/backoff.html - retryJitter: 200 // time in ms - }); - - redlock.on('clientError', logGenericError(__filename)); - module.exports.redlock = redlock; + lock.setup(module.exports.client); resolve({ server: redisUrl }); }); } -function lockRedisForAction(resourceId, ttl) { - log('warn', `Trying to lock redis for resource id ${resourceId}`, { resourceId, processId: process.pid }); - return module.exports.redlock.lock(resourceId, ttl); -} - -function unlockWhenReady(lock, resourceId, cb) { - return cb() - .then(result => module.exports.redlock.unlock(lock) - .then(() => { - log('warn', `Releasing lock for resource id ${resourceId}`, { resourceId, processId: process.pid }); - return result; - })); -} - -function getFromState(id) { - return module.exports.client.getAsync(id); -} - -function setState(action, state, expire) { - return module.exports.client.setAsync(action, state) - .then(() => { - if (expire) return module.exports.client.expire(action, expire); // Expire in 10 minutes - }); -} - -function sleepAndRun(cb, ms = 1000) { - return new Promise(resolve => setTimeout(() => cb().then(resolve), ms)); -} - -function applyLock(action, cb) { - const resourceId = `${action}-lock`, - ACTIONS = { - ONGOING: 'ON-GOING', - RETRY: 'RETRY', - FINISHED: 'FINISHED' - }, - RETRY_TIME = 1500, // ms - KEY_TTL = 10 * 60, // secs - LOCK_TTL = 5000; // ms - - return getFromState(action).then(state => { - /** - * If its ONGOING, just re-run this function after a while - * to see if the state changed. - */ - if (state === ACTIONS.ONGOING) { - return sleepAndRun(() => applyLock(action, cb), RETRY_TIME); - } - - if (!state || state === 'RETRY') return setState(action, ACTIONS.ONGOING) - .then(() => lockRedisForAction(resourceId, LOCK_TTL)) - .then(lock => unlockWhenReady(lock, resourceId, cb)) - .then(() => setState(action, ACTIONS.FINISHED, KEY_TTL)) - .catch(() => setState(action, ACTIONS.RETRY)); - }); -} - /** * Determines if we should write to cache * @@ -189,8 +112,7 @@ function del(key) { } module.exports.client = null; -module.exports.redlock; -module.exports.applyLock = applyLock; +module.exports.applyLock = lock.applyLock; module.exports.createClient = createClient; module.exports.get = get; module.exports.put = put; diff --git a/redis/lock.js b/redis/lock.js new file mode 100644 index 0000000..c09b791 --- /dev/null +++ b/redis/lock.js @@ -0,0 +1,115 @@ +'use strict'; + +const Redlock = require('redlock'), + { logGenericError } = require('../services/errors'), + emptyModule = { + lock: () => Promise.resolve(), + unlock: () => Promise.resolve() + }, + CONFIG = { + // the expected clock drift; for more details + // see http://redis.io/topics/distlock + driftFactor: 0.01, // time in ms + + // the max number of times Redlock will attempt + // to lock a resource before erroring + retryCount: 0, + + // the time in ms between attempts + retryDelay: 200, // time in ms + + // the max time in ms randomly added to retries + // to improve performance under high contention + // see https://www.awsarchitectureblog.com/2015/03/backoff.html + retryJitter: 200 // time in ms + }, + ACTION_RETRY_TOTAL = 5; + +let log = require('../services/log').setup({ file: __filename }), + ACTION_RETRY_COUNT = 0; + +function lockRedisForAction(resourceId, ttl) { + log('trace', `Trying to lock redis for resource id ${resourceId}`, { resourceId, processId: process.pid }); + return module.exports.redlock.lock(resourceId, ttl); +} + +function unlockWhenReady(lock, resourceId, cb) { + return cb() + .then(result => module.exports.redlock.unlock(lock) + .then(() => { + log('trace', `Releasing lock for resource id ${resourceId}`, { resourceId, processId: process.pid }); + return result; + })); +} + +function getFromState(id) { + return module.exports.redis.getAsync(id); +} + +function setState(action, state, expire) { + return module.exports.redis.setAsync(action, state) + .then(() => { + if (expire) return module.exports.redis.expire(action, expire); + }); +} + +function sleepAndRun(cb, ms = 1000) { + return new Promise(resolve => setTimeout(() => cb().then(resolve), ms)); +} + +function applyLock(action, cb) { + const resourceId = `${action}-lock`, + ACTIONS = { + ONGOING: 'ON-GOING', + RETRY: 'RETRY', + FINISHED: 'FINISHED' + }, + RETRY_TIME = 1500, // ms + KEY_TTL = 10 * 60, // secs + LOCK_TTL = 5000; // ms + + return getFromState(action).then(state => { + /** + * If its ONGOING, just re-run this function after a while + * to see if the state changed. + */ + if (state === ACTIONS.ONGOING) { + return sleepAndRun(() => applyLock(action, cb), RETRY_TIME); + } + + if (!state || state === 'RETRY') return setState(action, ACTIONS.ONGOING) + .then(() => lockRedisForAction(resourceId, LOCK_TTL)) + .then(lock => unlockWhenReady(lock, resourceId, cb)) + .then(() => setState(action, ACTIONS.FINISHED, KEY_TTL)) + .catch(() => { + ACTION_RETRY_COUNT++; + + if (ACTION_RETRY_COUNT === ACTION_RETRY_TOTAL) { + log('error', `Action "${action}" could not be executed`); + return setState(action, ACTIONS.FINISHED, KEY_TTL); + } + + return setState(action, ACTIONS.RETRY) + .then(() => sleepAndRun(() => applyLock(action, cb), RETRY_TIME)); + }); + }); +} + +function setup(instance) { + if (!instance) return emptyModule; + + const redlock = new Redlock([instance], CONFIG); + + redlock.on('clientError', logGenericError(__filename)); + + module.exports.redis = instance; + module.exports.redlock = redlock; + + return redlock; +} + +module.exports.redis = {}; +module.exports.redlock; + +module.exports.setup = setup; +module.exports.applyLock = applyLock; diff --git a/services/db.js b/services/db.js index cf501f1..a489c53 100644 --- a/services/db.js +++ b/services/db.js @@ -85,9 +85,7 @@ module.exports.put = put; module.exports.get = get; module.exports.del = del; module.exports.batch = batch; - module.exports.applyLock = redis.applyLock; - module.exports.raw = postgres.raw; module.exports.putMeta = postgres.putMeta; module.exports.getMeta = postgres.getMeta; From 4d513c5318083668c61730f2fd1af2930b9d6bcb Mon Sep 17 00:00:00 2001 From: James_Owen <35383768+james-owen@users.noreply.github.com> Date: Mon, 3 Jun 2019 09:57:28 -0400 Subject: [PATCH 06/24] Locking styling (#46) * prettier formatting * jsdoc setup * jsdoc started on all functions --- redis/lock.js | 94 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index c09b791..96c7c2e 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -28,35 +28,71 @@ const Redlock = require('redlock'), let log = require('../services/log').setup({ file: __filename }), ACTION_RETRY_COUNT = 0; +/** + * + * @param {*} resourceId + * @param {*} ttl + */ function lockRedisForAction(resourceId, ttl) { - log('trace', `Trying to lock redis for resource id ${resourceId}`, { resourceId, processId: process.pid }); + log('trace', `Trying to lock redis for resource id ${resourceId}`, { + resourceId, + processId: process.pid + }); return module.exports.redlock.lock(resourceId, ttl); } +/** + * + * @param {*} lock + * @param {*} resourceId + * @param {*} cb + */ function unlockWhenReady(lock, resourceId, cb) { - return cb() - .then(result => module.exports.redlock.unlock(lock) - .then(() => { - log('trace', `Releasing lock for resource id ${resourceId}`, { resourceId, processId: process.pid }); - return result; - })); + return cb().then(result => + module.exports.redlock.unlock(lock).then(() => { + log('trace', `Releasing lock for resource id ${resourceId}`, { + resourceId, + processId: process.pid + }); + return result; + }) + ); } +/** + * + * @param {*} id + */ function getFromState(id) { return module.exports.redis.getAsync(id); } +/** + * + * @param {*} action + * @param {*} state + * @param {*} expire + */ function setState(action, state, expire) { - return module.exports.redis.setAsync(action, state) - .then(() => { - if (expire) return module.exports.redis.expire(action, expire); - }); + return module.exports.redis.setAsync(action, state).then(() => { + if (expire) return module.exports.redis.expire(action, expire); + }); } +/** + * + * @param {*} cb + * @param {*} ms + */ function sleepAndRun(cb, ms = 1000) { return new Promise(resolve => setTimeout(() => cb().then(resolve), ms)); } +/** + * + * @param {*} action + * @param {*} cb + */ function applyLock(action, cb) { const resourceId = `${action}-lock`, ACTIONS = { @@ -77,24 +113,30 @@ function applyLock(action, cb) { return sleepAndRun(() => applyLock(action, cb), RETRY_TIME); } - if (!state || state === 'RETRY') return setState(action, ACTIONS.ONGOING) - .then(() => lockRedisForAction(resourceId, LOCK_TTL)) - .then(lock => unlockWhenReady(lock, resourceId, cb)) - .then(() => setState(action, ACTIONS.FINISHED, KEY_TTL)) - .catch(() => { - ACTION_RETRY_COUNT++; - - if (ACTION_RETRY_COUNT === ACTION_RETRY_TOTAL) { - log('error', `Action "${action}" could not be executed`); - return setState(action, ACTIONS.FINISHED, KEY_TTL); - } - - return setState(action, ACTIONS.RETRY) - .then(() => sleepAndRun(() => applyLock(action, cb), RETRY_TIME)); - }); + if (!state || state === 'RETRY') + return setState(action, ACTIONS.ONGOING) + .then(() => lockRedisForAction(resourceId, LOCK_TTL)) + .then(lock => unlockWhenReady(lock, resourceId, cb)) + .then(() => setState(action, ACTIONS.FINISHED, KEY_TTL)) + .catch(() => { + ACTION_RETRY_COUNT++; + + if (ACTION_RETRY_COUNT === ACTION_RETRY_TOTAL) { + log('error', `Action "${action}" could not be executed`); + return setState(action, ACTIONS.FINISHED, KEY_TTL); + } + + return setState(action, ACTIONS.RETRY).then(() => + sleepAndRun(() => applyLock(action, cb), RETRY_TIME) + ); + }); }); } +/** + * + * @param {*} instance + */ function setup(instance) { if (!instance) return emptyModule; From 735e282990ce1a395b2388596ab522ac4296fb96 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Mon, 3 Jun 2019 17:03:31 -0400 Subject: [PATCH 07/24] Update variables and JSDoc types --- redis/lock.js | 59 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index 96c7c2e..bc94cd5 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -23,15 +23,16 @@ const Redlock = require('redlock'), // see https://www.awsarchitectureblog.com/2015/03/backoff.html retryJitter: 200 // time in ms }, - ACTION_RETRY_TOTAL = 5; + action_retry_total = 5; let log = require('../services/log').setup({ file: __filename }), - ACTION_RETRY_COUNT = 0; + action_retry_count = 0; /** * - * @param {*} resourceId - * @param {*} ttl + * @param {string} resourceId + * @param {number} ttl + * @returns {Promise} */ function lockRedisForAction(resourceId, ttl) { log('trace', `Trying to lock redis for resource id ${resourceId}`, { @@ -43,9 +44,10 @@ function lockRedisForAction(resourceId, ttl) { /** * - * @param {*} lock - * @param {*} resourceId - * @param {*} cb + * @param {Object} lock + * @param {string} resourceId + * @param {Function} cb + * @returns {Promise} */ function unlockWhenReady(lock, resourceId, cb) { return cb().then(result => @@ -61,7 +63,8 @@ function unlockWhenReady(lock, resourceId, cb) { /** * - * @param {*} id + * @param {string} id + * @returns {Promise} */ function getFromState(id) { return module.exports.redis.getAsync(id); @@ -69,9 +72,10 @@ function getFromState(id) { /** * - * @param {*} action - * @param {*} state - * @param {*} expire + * @param {string} action + * @param {string} state + * @param {number} expire + * @returns {Promise} */ function setState(action, state, expire) { return module.exports.redis.setAsync(action, state).then(() => { @@ -81,8 +85,9 @@ function setState(action, state, expire) { /** * - * @param {*} cb - * @param {*} ms + * @param {Function} cb + * @param {number} ms + * @returns {Promise} */ function sleepAndRun(cb, ms = 1000) { return new Promise(resolve => setTimeout(() => cb().then(resolve), ms)); @@ -90,12 +95,13 @@ function sleepAndRun(cb, ms = 1000) { /** * - * @param {*} action - * @param {*} cb + * @param {string} action + * @param {Function} cb + * @returns {Promise} */ function applyLock(action, cb) { const resourceId = `${action}-lock`, - ACTIONS = { + STATE = { ONGOING: 'ON-GOING', RETRY: 'RETRY', FINISHED: 'FINISHED' @@ -106,27 +112,27 @@ function applyLock(action, cb) { return getFromState(action).then(state => { /** - * If its ONGOING, just re-run this function after a while + * If it's ONGOING, just re-run this function after a while * to see if the state changed. */ - if (state === ACTIONS.ONGOING) { + if (state === STATE.ONGOING) { return sleepAndRun(() => applyLock(action, cb), RETRY_TIME); } - if (!state || state === 'RETRY') - return setState(action, ACTIONS.ONGOING) + if (!state || state === STATE.RETRY) + return setState(action, STATE.ONGOING) .then(() => lockRedisForAction(resourceId, LOCK_TTL)) .then(lock => unlockWhenReady(lock, resourceId, cb)) - .then(() => setState(action, ACTIONS.FINISHED, KEY_TTL)) + .then(() => setState(action, STATE.FINISHED, KEY_TTL)) .catch(() => { - ACTION_RETRY_COUNT++; + action_retry_count++; - if (ACTION_RETRY_COUNT === ACTION_RETRY_TOTAL) { + if (action_retry_count === action_retry_total) { log('error', `Action "${action}" could not be executed`); - return setState(action, ACTIONS.FINISHED, KEY_TTL); + return setState(action, STATE.FINISHED, KEY_TTL); } - return setState(action, ACTIONS.RETRY).then(() => + return setState(action, STATE.RETRY).then(() => sleepAndRun(() => applyLock(action, cb), RETRY_TIME) ); }); @@ -135,7 +141,8 @@ function applyLock(action, cb) { /** * - * @param {*} instance + * @param {Object} instance + * @returns {Object} */ function setup(instance) { if (!instance) return emptyModule; From 0067849651ac31ab74f3ddb981d2be55f33b09d8 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Tue, 4 Jun 2019 11:18:26 -0400 Subject: [PATCH 08/24] Add description to the functions --- redis/lock.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index bc94cd5..7af8f0c 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -29,6 +29,8 @@ let log = require('../services/log').setup({ file: __filename }), action_retry_count = 0; /** + * Adds a lock to redis with the given id + * for a determined period of time * * @param {string} resourceId * @param {number} ttl @@ -43,10 +45,12 @@ function lockRedisForAction(resourceId, ttl) { } /** + * Unlocks the specified lock + * when the callback returns * * @param {Object} lock * @param {string} resourceId - * @param {Function} cb + * @param {Function} cb Must return a promise * @returns {Promise} */ function unlockWhenReady(lock, resourceId, cb) { @@ -62,6 +66,7 @@ function unlockWhenReady(lock, resourceId, cb) { } /** + * Gets the value of the specified id in redis * * @param {string} id * @returns {Promise} @@ -84,6 +89,7 @@ function setState(action, state, expire) { } /** + * Waits an amount of time, then runs the callback * * @param {Function} cb * @param {number} ms @@ -140,9 +146,11 @@ function applyLock(action, cb) { } /** + * Saves both the redis and redlock instance + * into the module * - * @param {Object} instance - * @returns {Object} + * @param {Object} instance Redis instance + * @returns {Object} Redlock instance */ function setup(instance) { if (!instance) return emptyModule; From 3861b1d917ad8737294a4b97a23c7be872f40980 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Tue, 4 Jun 2019 11:27:58 -0400 Subject: [PATCH 09/24] Removing underscore from variables --- redis/lock.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index 7af8f0c..bbc3c67 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -23,10 +23,10 @@ const Redlock = require('redlock'), // see https://www.awsarchitectureblog.com/2015/03/backoff.html retryJitter: 200 // time in ms }, - action_retry_total = 5; + actionRetryTotal = 5; let log = require('../services/log').setup({ file: __filename }), - action_retry_count = 0; + actionRetryCount = 0; /** * Adds a lock to redis with the given id @@ -131,9 +131,9 @@ function applyLock(action, cb) { .then(lock => unlockWhenReady(lock, resourceId, cb)) .then(() => setState(action, STATE.FINISHED, KEY_TTL)) .catch(() => { - action_retry_count++; + actionRetryCount++; - if (action_retry_count === action_retry_total) { + if (actionRetryCount >= actionRetryTotal) { log('error', `Action "${action}" could not be executed`); return setState(action, STATE.FINISHED, KEY_TTL); } From b4542f665c712b7ce1e46d45d432b749ab1627cd Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Tue, 4 Jun 2019 11:42:43 -0400 Subject: [PATCH 10/24] Change function name to setupRedlock --- redis/index.js | 2 +- redis/lock.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/redis/index.js b/redis/index.js index ac6918d..ab69964 100644 --- a/redis/index.js +++ b/redis/index.js @@ -28,7 +28,7 @@ function createClient(testRedisUrl) { module.exports.client = bluebird.promisifyAll(new Redis(redisUrl)); module.exports.client.on('error', logGenericError(__filename)); - lock.setup(module.exports.client); + lock.setupRedlock(module.exports.client); resolve({ server: redisUrl }); }); diff --git a/redis/lock.js b/redis/lock.js index bbc3c67..d970e7e 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -152,7 +152,7 @@ function applyLock(action, cb) { * @param {Object} instance Redis instance * @returns {Object} Redlock instance */ -function setup(instance) { +function setupRedlock(instance) { if (!instance) return emptyModule; const redlock = new Redlock([instance], CONFIG); @@ -168,5 +168,5 @@ function setup(instance) { module.exports.redis = {}; module.exports.redlock; -module.exports.setup = setup; +module.exports.setupRedlock = setupRedlock; module.exports.applyLock = applyLock; From 4fc61113b0e73a767dbeab8abda01db7cbd9d69e Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Wed, 5 Jun 2019 10:42:57 -0400 Subject: [PATCH 11/24] Abstract some functions --- redis/lock.js | 55 ++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index d970e7e..c249ab6 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -23,6 +23,14 @@ const Redlock = require('redlock'), // see https://www.awsarchitectureblog.com/2015/03/backoff.html retryJitter: 200 // time in ms }, + STATE = { + ONGOING: 'ON-GOING', + RETRY: 'RETRY', + FINISHED: 'FINISHED' + }, + RETRY_TIME = 1500, // ms + KEY_TTL = 10 * 60, // secs + LOCK_TTL = 5000, // ms actionRetryTotal = 5; let log = require('../services/log').setup({ file: __filename }), @@ -106,15 +114,7 @@ function sleepAndRun(cb, ms = 1000) { * @returns {Promise} */ function applyLock(action, cb) { - const resourceId = `${action}-lock`, - STATE = { - ONGOING: 'ON-GOING', - RETRY: 'RETRY', - FINISHED: 'FINISHED' - }, - RETRY_TIME = 1500, // ms - KEY_TTL = 10 * 60, // secs - LOCK_TTL = 5000; // ms + const resourceId = `${action}-lock`; return getFromState(action).then(state => { /** @@ -126,25 +126,30 @@ function applyLock(action, cb) { } if (!state || state === STATE.RETRY) - return setState(action, STATE.ONGOING) - .then(() => lockRedisForAction(resourceId, LOCK_TTL)) - .then(lock => unlockWhenReady(lock, resourceId, cb)) - .then(() => setState(action, STATE.FINISHED, KEY_TTL)) - .catch(() => { - actionRetryCount++; - - if (actionRetryCount >= actionRetryTotal) { - log('error', `Action "${action}" could not be executed`); - return setState(action, STATE.FINISHED, KEY_TTL); - } - - return setState(action, STATE.RETRY).then(() => - sleepAndRun(() => applyLock(action, cb), RETRY_TIME) - ); - }); + return startLocking(action, resourceId, cb) + .catch(() => retryLocking(action, cb)); }); } +function startLocking(action, resourceId, cb) { + return setState(action, STATE.ONGOING) + .then(() => lockRedisForAction(resourceId, LOCK_TTL)) + .then(lock => unlockWhenReady(lock, resourceId, cb)) + .then(() => setState(action, STATE.FINISHED, KEY_TTL)); +} + +function retryLocking(action, cb) { + actionRetryCount++; + + if (actionRetryCount >= actionRetryTotal) { + log('error', `Action "${action}" could not be executed`); + return setState(action, STATE.FINISHED, KEY_TTL); + } + + return setState(action, STATE.RETRY) + .then(() => sleepAndRun(() => applyLock(action, cb), RETRY_TIME)); +} + /** * Saves both the redis and redlock instance * into the module From 4db3f8daaffd8be6842053b46bb4123bf1d814bf Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Wed, 5 Jun 2019 11:07:22 -0400 Subject: [PATCH 12/24] Rename functions and parameters --- redis/lock.js | 57 ++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index c249ab6..d2f717c 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -37,35 +37,35 @@ let log = require('../services/log').setup({ file: __filename }), actionRetryCount = 0; /** - * Adds a lock to redis with the given id + * Adds a lock to redis with the given lockName * for a determined period of time * - * @param {string} resourceId + * @param {string} lockName * @param {number} ttl * @returns {Promise} */ -function lockRedisForAction(resourceId, ttl) { - log('trace', `Trying to lock redis for resource id ${resourceId}`, { - resourceId, +function addLock(lockName, ttl) { + log('trace', `Trying to lock redis for resource id ${lockName}`, { + lockName, processId: process.pid }); - return module.exports.redlock.lock(resourceId, ttl); + return module.exports.redlock.lock(lockName, ttl); } /** - * Unlocks the specified lock + * Removes the specified lock * when the callback returns * * @param {Object} lock - * @param {string} resourceId + * @param {string} lockName * @param {Function} cb Must return a promise * @returns {Promise} */ -function unlockWhenReady(lock, resourceId, cb) { +function removeLockWhenReady(lock, lockName, cb) { return cb().then(result => module.exports.redlock.unlock(lock).then(() => { - log('trace', `Releasing lock for resource id ${resourceId}`, { - resourceId, + log('trace', `Releasing lock for resource id ${lockName}`, { + lockName, processId: process.pid }); return result; @@ -74,25 +74,26 @@ function unlockWhenReady(lock, resourceId, cb) { } /** - * Gets the value of the specified id in redis + * Gets the value of the specified key in redis * - * @param {string} id + * @param {string} key * @returns {Promise} */ -function getFromState(id) { - return module.exports.redis.getAsync(id); +function getState(key) { + return module.exports.redis.getAsync(key); } /** - * - * @param {string} action - * @param {string} state - * @param {number} expire + * Sets a key-value pair into redis. + * This key will have an expire time if specified + * @param {string} key + * @param {string} value + * @param {number} expireTime * @returns {Promise} */ -function setState(action, state, expire) { - return module.exports.redis.setAsync(action, state).then(() => { - if (expire) return module.exports.redis.expire(action, expire); +function setState(key, value, expireTime) { + return module.exports.redis.setAsync(key, value).then(() => { + if (expireTime) return module.exports.redis.expire(key, expireTime); }); } @@ -114,9 +115,9 @@ function sleepAndRun(cb, ms = 1000) { * @returns {Promise} */ function applyLock(action, cb) { - const resourceId = `${action}-lock`; + const lockName = `${action}-lock`; - return getFromState(action).then(state => { + return getState(action).then(state => { /** * If it's ONGOING, just re-run this function after a while * to see if the state changed. @@ -126,15 +127,15 @@ function applyLock(action, cb) { } if (!state || state === STATE.RETRY) - return startLocking(action, resourceId, cb) + return lockAndExecute(action, lockName, cb) .catch(() => retryLocking(action, cb)); }); } -function startLocking(action, resourceId, cb) { +function lockAndExecute(action, lockName, cb) { return setState(action, STATE.ONGOING) - .then(() => lockRedisForAction(resourceId, LOCK_TTL)) - .then(lock => unlockWhenReady(lock, resourceId, cb)) + .then(() => addLock(lockName, LOCK_TTL)) + .then(lock => removeLockWhenReady(lock, lockName, cb)) .then(() => setState(action, STATE.FINISHED, KEY_TTL)); } From 675e1bc47997433970f1c306ece5ea1a2080e5d9 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Thu, 6 Jun 2019 15:41:13 -0400 Subject: [PATCH 13/24] Update package-lock --- package-lock.json | 1564 +++++++++++++++++++++++++-------------------- 1 file changed, 870 insertions(+), 694 deletions(-) diff --git a/package-lock.json b/package-lock.json index 43a9408..8013d40 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,15 +31,15 @@ "dev": true }, "acorn": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz", - "integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", "dev": true }, "acorn-globals": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", - "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz", + "integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==", "dev": true, "requires": { "acorn": "^6.0.1", @@ -59,9 +59,9 @@ "dev": true }, "ajv": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.1.tgz", - "integrity": "sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -82,16 +82,15 @@ } }, "ansi-escapes": { - "version": "3.1.0", - "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "3.2.1", @@ -150,7 +149,7 @@ }, "array-equal": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", "dev": true }, @@ -197,12 +196,12 @@ "dev": true }, "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { - "lodash": "^4.17.10" + "lodash": "^4.17.11" } }, "async-limiter": { @@ -245,12 +244,6 @@ "js-tokens": "^3.0.2" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", @@ -259,7 +252,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -276,15 +269,6 @@ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", "dev": true }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -328,6 +312,12 @@ "requires": { "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, @@ -378,7 +368,7 @@ }, "babel-plugin-istanbul": { "version": "4.1.6", - "resolved": "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", "dev": true, "requires": { @@ -386,6 +376,17 @@ "find-up": "^2.1.0", "istanbul-lib-instrument": "^1.10.1", "test-exclude": "^4.2.1" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + } } }, "babel-plugin-jest-hoist": { @@ -396,7 +397,7 @@ }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "dev": true }, @@ -478,6 +479,12 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, @@ -564,9 +571,9 @@ } }, "bluebird": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" }, "brace-expansion": { "version": "1.1.11", @@ -621,7 +628,7 @@ "dependencies": { "resolve": { "version": "1.1.7", - "resolved": "http://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true } @@ -644,14 +651,9 @@ }, "buffer-writer": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz", "integrity": "sha1-Iqk2kB4wKa/NdUfrRIfOtpejvwg=" }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -668,26 +670,16 @@ "unset-value": "^1.0.0" } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "^0.2.0" - } - }, "callsites": { - "version": "0.2.0", - "resolved": "http://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" }, "capture-exit": { "version": "1.2.0", @@ -705,9 +697,9 @@ "dev": true }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -726,12 +718,6 @@ "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", "dev": true }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -788,13 +774,12 @@ "dev": true }, "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", "wrap-ansi": "^2.0.0" } }, @@ -837,23 +822,23 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "requires": { "delayed-stream": "~1.0.0" } }, "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "concat-map": { "version": "0.0.1", @@ -875,9 +860,9 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "core-js": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.0.tgz", - "integrity": "sha512-kLRC6ncVpuEW/1kwrOXYX6KQASCVtrh1gQr/UiaVgFlf9WE5Vp+lNe5+h3LuMr5PAucWnnEXwH0nQHRH/gpGtw==" + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==" }, "core-util-is": { "version": "1.0.2", @@ -885,9 +870,9 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "coveralls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.2.tgz", - "integrity": "sha512-Tv0LKe/MkBOilH2v7WBiTBdudg2ChfGbdXafc/s330djpF3zKOmuehTeRwjXWc7pzfj9FrDUTA7tEx6Div8NFw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.4.tgz", + "integrity": "sha512-eyqUWA/7RT0JagiL0tThVhjbIjoiEUyWCjtUJoOPcWoeofP5WK/jb2OJYoBFrR6DvplR+AxOyuBqk4JHkk5ykA==", "dev": true, "requires": { "growl": "~> 1.10.0", @@ -895,7 +880,7 @@ "lcov-parse": "^0.0.10", "log-driver": "^1.2.7", "minimist": "^1.2.0", - "request": "^2.85.0" + "request": "^2.86.0" } }, "cross-spawn": { @@ -912,23 +897,23 @@ }, "dependencies": { "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true } } }, "cssom": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz", - "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==", "dev": true }, "cssstyle": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.1.1.tgz", - "integrity": "sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz", + "integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==", "dev": true, "requires": { "cssom": "0.3.x" @@ -968,11 +953,11 @@ } }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "decamelize": { @@ -1058,9 +1043,9 @@ "dev": true }, "denque": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.0.tgz", - "integrity": "sha512-gh513ac7aiKrAgjiIBWZG0EASyDF9p4JMWwKA8YU5s9figrL5SRNEMT6FDynsegakuhWd1wVqTvqvqAoDxw7wQ==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" }, "detect-file": { "version": "1.0.0", @@ -1089,9 +1074,9 @@ "dev": true }, "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -1116,6 +1101,12 @@ "safer-buffer": "^2.1.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -1133,16 +1124,17 @@ } }, "es-abstract": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", "dev": true, "requires": { - "es-to-primitive": "^1.1.1", + "es-to-primitive": "^1.2.0", "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" } }, "es-to-primitive": { @@ -1162,9 +1154,9 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.0.tgz", - "integrity": "sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", + "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", "dev": true, "requires": { "esprima": "^3.1.3", @@ -1190,77 +1182,85 @@ } }, "eslint": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.10.0.tgz", - "integrity": "sha512-HpqzC+BHULKlnPwWae9MaVZ5AXJKpkxCVXQHrFaRw3hbDj26V/9ArYM4Rr/SQ8pi6qUPLXSSXC4RBJlyq2Z2OQ==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", + "ajv": "^6.9.1", "chalk": "^2.1.0", "cross-spawn": "^6.0.5", "debug": "^4.0.1", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.0", + "espree": "^5.0.1", "esquery": "^1.0.1", "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", + "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob": "^7.1.2", "globals": "^11.7.0", "ignore": "^4.0.6", + "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", - "js-yaml": "^3.12.0", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", - "lodash": "^4.17.5", + "lodash": "^4.17.11", "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", "progress": "^2.0.0", "regexpp": "^2.0.1", - "require-uncached": "^1.0.3", "semver": "^5.5.1", "strip-ansi": "^4.0.0", "strip-json-comments": "^2.0.1", - "table": "^5.0.2", + "table": "^5.2.3", "text-table": "^0.2.0" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { "ms": "^2.1.1" } }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - }, "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } } } }, "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -1280,12 +1280,12 @@ "dev": true }, "espree": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.0.tgz", - "integrity": "sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", "dev": true, "requires": { - "acorn": "^6.0.2", + "acorn": "^6.0.7", "acorn-jsx": "^5.0.0", "eslint-visitor-keys": "^1.0.0" } @@ -1405,12 +1405,17 @@ "requires": { "is-extendable": "^0.1.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, "expand-range": { "version": "1.8.2", - "resolved": "http://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { @@ -1628,13 +1633,12 @@ } }, "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", "dev": true, "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "flat-cache": "^2.0.1" } }, "filename-regex": { @@ -1675,12 +1679,12 @@ } }, "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "requires": { - "locate-path": "^2.0.0" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "findup-sync": { @@ -1695,9 +1699,9 @@ } }, "fined": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.1.tgz", - "integrity": "sha512-jQp949ZmEbiYHk3gkbdtpJ0G1+kgtLQBNdP5edFP7Fh+WAYceLQz6yO1SBj72Xkg8GVyTB3bBzAYrHJVh5Xd5g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "requires": { "expand-tilde": "^2.0.2", "is-plain-object": "^2.0.3", @@ -1712,26 +1716,26 @@ "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" }, "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", "dev": true, "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" } }, "flatstr": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.9.tgz", - "integrity": "sha512-qFlJnOBWDfIaunF54/lBqNKmXOI0HqNhu+mHkLmbaBXlS71PUd9OjFOdyevHt/aHoHB1+eW7eKHgRKOG5aHSpw==" + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz", + "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" }, - "flexbuffer": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/flexbuffer/-/flexbuffer-0.0.6.tgz", - "integrity": "sha1-A5/fI/iCPkQMOPMnfm/vEXQhWzA=" + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", + "dev": true }, "for-in": { "version": "1.0.2", @@ -1777,14 +1781,14 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { @@ -1796,8 +1800,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -1806,7 +1809,7 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, @@ -1818,21 +1821,19 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -1840,20 +1841,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -1862,16 +1860,16 @@ "optional": true }, "debug": { - "version": "2.6.9", + "version": "4.1.1", "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -1920,7 +1918,7 @@ } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, @@ -1940,12 +1938,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -1970,8 +1968,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -1983,7 +1980,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1998,7 +1994,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2006,21 +2001,19 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, @@ -2032,41 +2025,40 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } }, "ms": { - "version": "2.0.0", + "version": "2.1.1", "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.3.0", "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", + "debug": "^4.1.0", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.12.0", "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", - "needle": "^2.2.0", + "needle": "^2.2.1", "nopt": "^4.0.1", "npm-packlist": "^1.1.6", "npmlog": "^4.0.2", - "rc": "^1.1.7", + "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", "tar": "^4" @@ -2083,13 +2075,13 @@ } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.6", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.4.1", "bundled": true, "dev": true, "optional": true, @@ -2113,8 +2105,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -2126,7 +2117,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -2166,12 +2156,12 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -2201,19 +2191,18 @@ } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -2228,7 +2217,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.7.0", "bundled": true, "dev": true, "optional": true @@ -2249,7 +2238,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2269,7 +2257,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2281,17 +2268,17 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.2" } }, @@ -2302,25 +2289,23 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -2348,7 +2333,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, @@ -2367,9 +2352,9 @@ } }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2455,9 +2440,9 @@ } }, "globals": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", - "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "graceful-fs": { @@ -2478,12 +2463,12 @@ "dev": true }, "handlebars": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", - "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", "dev": true, "requires": { - "async": "^2.5.0", + "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" @@ -2529,14 +2514,6 @@ "dev": true, "requires": { "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - } } }, "has-flag": { @@ -2580,9 +2557,9 @@ } }, "highland": { - "version": "2.13.0", - "resolved": "http://registry.npmjs.org/highland/-/highland-2.13.0.tgz", - "integrity": "sha512-zGZBcgAHPY2Zf9VG9S5IrlcC7CH9ELioXVtp9T5bU2a4fP2zIsA+Y8pV/n/h2lMwbWMHTX0I0xN0ODJ3Pd3aBQ==", + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/highland/-/highland-2.13.4.tgz", + "integrity": "sha512-r+YlbnBhCTcrcVzBpzPcrvB0llVjeDWKuXSZVuNBe5WgQJtN2xGUUMZC9WzHCntNIx0rskVernxLoFJUCkmb/Q==", "requires": { "util-deprecate": "^1.0.2" } @@ -2598,9 +2575,9 @@ } }, "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "requires": { "parse-passwd": "^1.0.0" } @@ -2645,6 +2622,16 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "import-fresh": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "import-local": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", @@ -2681,47 +2668,82 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "inquirer": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", - "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", + "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "external-editor": "^3.0.0", + "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "mute-stream": "0.0.7", "run-async": "^2.2.0", - "rxjs": "^6.1.0", + "rxjs": "^6.4.0", "string-width": "^2.1.0", - "strip-ansi": "^5.0.0", + "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { "ansi-regex": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", - "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "strip-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", - "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^4.0.0" + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } } } }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" }, "invariant": { "version": "2.2.4", @@ -2738,30 +2760,19 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, "ioredis": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.3.0.tgz", - "integrity": "sha512-TwTp93UDKlKVQeg9ThuavNh4Vs31JTlqn+cI/J6z21OtfghyJm5I349ZlsKobOeEyS4INITMLQ1fhR7xwf9Fxg==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.9.5.tgz", + "integrity": "sha512-L9MVfvX4F3LScTMEgriCGixzqinJsYy7Mt0NPX8RyuOTmx5JW0744pM4Ze2KVQcP3J0zvKYZ1LywAB6KIq7PYg==", "requires": { "cluster-key-slot": "^1.0.6", "debug": "^3.1.0", "denque": "^1.1.0", - "flexbuffer": "0.0.6", "lodash.defaults": "^4.2.0", "lodash.flatten": "^4.4.0", "redis-commands": "1.4.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", - "standard-as-callback": "^1.0.0" - }, - "dependencies": { - "redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", - "requires": { - "redis-errors": "^1.0.0" - } - } + "standard-as-callback": "^2.0.1" } }, "is-absolute": { @@ -2801,14 +2812,6 @@ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "^1.0.0" - } - }, "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", @@ -2900,10 +2903,12 @@ } }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } }, "is-generator-fn": { "version": "1.0.0", @@ -3019,6 +3024,12 @@ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -3090,9 +3101,9 @@ }, "dependencies": { "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true } } @@ -3158,6 +3169,12 @@ "jest-cli": "^23.6.0" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", @@ -3184,6 +3201,23 @@ "repeat-element": "^1.1.2" } }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, "expand-brackets": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", @@ -3202,12 +3236,27 @@ "is-extglob": "^1.0.0" } }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", "dev": true }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", @@ -3290,11 +3339,76 @@ "parse-glob": "^3.0.4", "regex-cache": "^0.4.2" } - } - } - }, - "jest-changed-files": { - "version": "23.4.2", + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "yargs": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", + "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "jest-changed-files": { + "version": "23.4.2", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-23.4.2.tgz", "integrity": "sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA==", "dev": true, @@ -3469,7 +3583,7 @@ }, "jest-get-type": { "version": "22.4.3", - "resolved": "http://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", "dev": true }, @@ -3785,9 +3899,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", - "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -3825,6 +3939,12 @@ "yargs": "^11.0.0" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, "arr-diff": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", @@ -3851,6 +3971,23 @@ "repeat-element": "^1.1.2" } }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, "expand-brackets": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", @@ -3869,12 +4006,27 @@ "is-extglob": "^1.0.0" } }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", "dev": true }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", @@ -3914,11 +4066,76 @@ "regex-cache": "^0.4.2" } }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "yargs": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", + "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } } } }, @@ -3947,9 +4164,9 @@ }, "dependencies": { "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true } } @@ -3972,7 +4189,7 @@ "dependencies": { "callsites": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", "dev": true }, @@ -4028,9 +4245,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -4086,7 +4303,7 @@ }, "jsesc": { "version": "1.3.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true }, @@ -4116,7 +4333,7 @@ }, "json5": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "dev": true }, @@ -4168,13 +4385,26 @@ "dependencies": { "chalk": { "version": "2.3.2", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, @@ -4231,7 +4461,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { "graceful-fs": "^4.1.2", @@ -4249,6 +4479,14 @@ "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } } }, "lodash": { @@ -4333,9 +4571,9 @@ } }, "math-random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", "dev": true }, "mem": { @@ -4383,18 +4621,18 @@ } }, "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", "dev": true }, "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", "dev": true, "requires": { - "mime-db": "~1.37.0" + "mime-db": "1.40.0" } }, "mimic-fn": { @@ -4413,7 +4651,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "mixin-deep": { @@ -4437,7 +4675,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -4445,15 +4683,15 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" } } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "mute-stream": { "version": "0.0.7", @@ -4462,9 +4700,9 @@ "dev": true }, "nan": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", - "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true, "optional": true }, @@ -4492,6 +4730,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -4505,32 +4749,33 @@ "dev": true }, "node-notifier": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz", - "integrity": "sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", + "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", "dev": true, "requires": { "growly": "^1.3.0", + "is-wsl": "^1.1.0", "semver": "^5.5.0", "shellwords": "^0.1.1", "which": "^1.3.0" }, "dependencies": { "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true } } }, "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "requires": { "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", + "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } @@ -4559,9 +4804,9 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nwsapi": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz", - "integrity": "sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", + "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", "dev": true }, "nymag-fs": { @@ -4581,10 +4826,9 @@ "dev": true }, "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" }, "object-copy": { "version": "0.1.0", @@ -4615,9 +4859,9 @@ } }, "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object-visit": { @@ -4716,7 +4960,7 @@ "dependencies": { "minimist": { "version": "0.0.10", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "dev": true }, @@ -4744,23 +4988,20 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "dev": true, + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" + "lcid": "^1.0.0" } }, "os-tmpdir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, @@ -4799,6 +5040,15 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz", "integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc=" }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", @@ -4863,14 +5113,16 @@ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { @@ -4956,9 +5208,9 @@ "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" }, "pg-pool": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.5.tgz", - "integrity": "sha512-T4W9qzP2LjItXuXbW6jgAF2AY0jHp6IoTxRhM3GB7yzfBxzDnA3GCm0sAduzmmiCybMqD0+V1HiqIG5X2YWqlQ==" + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.6.tgz", + "integrity": "sha512-hod2zYQxM8Gt482q+qONGTYcg/qVcV32VHVPtktbBJs0us3Dj7xibISw0BAAXVMCzt8A/jhfJvpZaxUlqtqs0g==" }, "pg-query-stream": { "version": "1.1.2", @@ -4998,47 +5250,6 @@ "yargs": "^5.0.0" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "object-assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", - "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" - }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "requires": { - "lcid": "^1.0.0" - } - }, "pg": { "version": "6.4.2", "resolved": "https://registry.npmjs.org/pg/-/pg-6.4.2.tgz", @@ -5067,65 +5278,12 @@ "generic-pool": "2.4.3", "object-assign": "4.1.0" } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" - }, - "yargs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz", - "integrity": "sha1-M1UUSXfQV1fbuG1uOOwFYSOzpm4=", - "requires": { - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "lodash.assign": "^4.2.0", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "window-size": "^0.2.0", - "y18n": "^3.2.1", - "yargs-parser": "^3.2.0" - } - }, - "yargs-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz", - "integrity": "sha1-UIE1XRnZ0MjF2BrakIy05tGGZk8=", - "requires": { - "camelcase": "^3.0.0", - "lodash.assign": "^4.1.0" - } } } }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" }, "pinkie": { @@ -5157,9 +5315,9 @@ } }, "pino-std-serializers": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.3.0.tgz", - "integrity": "sha512-klfGoOsP6sJH7ON796G4xoUSx2fkpFgKHO4YVVO2zmz31jR+etzc/QzGJILaOIiCD6HTCFgkPx+XN8nk+ruqPw==" + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.4.2.tgz", + "integrity": "sha512-WaL504dO8eGs+vrK+j4BuQQq6GLKeCCcHaMB2ItygzVURcL1CycwNEUHTD/lHFHs/NL5qAz2UKrjYWXKSf4aMQ==" }, "pkg-dir": { "version": "2.0.0", @@ -5168,14 +5326,19 @@ "dev": true, "requires": { "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + } } }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true - }, "pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", @@ -5198,14 +5361,14 @@ "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" }, "postgres-date": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.3.tgz", - "integrity": "sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g=" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.4.tgz", + "integrity": "sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA==" }, "postgres-interval": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.2.tgz", - "integrity": "sha512-fC3xNHeTskCxL1dC8KOtxXt7YeFmlbTYtn7ul8MkVERuTmf7pI4DrkAxcw3kh1fQ9uz4wQmd03a1mRiXUZChfQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", "requires": { "xtend": "^4.0.0" } @@ -5232,9 +5395,9 @@ "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, "pg": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-7.10.0.tgz", - "integrity": "sha512-aE6FZomsyn3OeGv1oM50v7Xu5zR75c15LXdOCwA9GGrfjXsQjzwYpbcTS6OwEMhYfZQS6m/FVU/ilPLiPzJDCw==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.11.0.tgz", + "integrity": "sha512-YO4V7vCmEMGoF390LJaFaohWNKaA2ayoQOEZmiHVcAUF+YsRThpf/TaKCgSvsSE7cDm37Q/Cy3Gz41xiX/XjTw==", "requires": { "buffer-writer": "2.0.0", "packet-reader": "1.0.0", @@ -5266,11 +5429,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - }, - "postgres-date": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.4.tgz", - "integrity": "sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA==" } } }, @@ -5294,6 +5452,14 @@ "requires": { "ansi-regex": "^3.0.0", "ansi-styles": "^3.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } } }, "private": { @@ -5330,9 +5496,9 @@ "dev": true }, "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "version": "1.1.32", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", + "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==", "dev": true }, "pump": { @@ -5400,30 +5566,11 @@ "requires": { "find-up": "^1.0.0", "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "^2.0.0" - } - } } }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -5436,9 +5583,9 @@ } }, "realpath-native": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.2.tgz", - "integrity": "sha512-+S3zTvVt9yTntFrBpm7TQmQ3tzpCrnA1a/y+3cUHAc9ZR6aIjG0WNLR+Rj79QpJktY+VeW/TQtFlQ1bzsehI8g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", "dev": true, "requires": { "util.promisify": "^1.0.0" @@ -5462,6 +5609,22 @@ "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "requires": { + "redis-errors": "^1.0.0" + } + }, + "redlock": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/redlock/-/redlock-3.1.2.tgz", + "integrity": "sha512-CKXhOvLd4In5QOfbcF0GIcSsa+pL9JPZd+eKeMk/Sydxh93NUNtwQMTIKFqwPu3PjEgDStwYFJTurVzNA33pZw==", + "requires": { + "bluebird": "^3.3.3" + } + }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", @@ -5545,23 +5708,23 @@ } }, "request-promise-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", - "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", "dev": true, "requires": { - "lodash": "^4.13.1" + "lodash": "^4.17.11" } }, "request-promise-native": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", - "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", "dev": true, "requires": { - "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" } }, "require-directory": { @@ -5574,22 +5737,12 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, - "require-uncached": { - "version": "1.0.3", - "resolved": "http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - } - }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "resolve-cwd": { @@ -5619,9 +5772,9 @@ } }, "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "resolve-url": { @@ -5645,12 +5798,12 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "rsvp": { @@ -5669,9 +5822,9 @@ } }, "rxjs": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", - "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -5684,7 +5837,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -5721,7 +5874,7 @@ }, "semver": { "version": "4.3.2", - "resolved": "http://registry.npmjs.org/semver/-/semver-4.3.2.tgz", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=" }, "set-blocking": { @@ -5790,14 +5943,22 @@ "dev": true }, "slice-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.0.0.tgz", - "integrity": "sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, "requires": { "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } } }, "snapdragon": { @@ -5838,6 +5999,11 @@ "requires": { "is-extendable": "^0.1.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, @@ -5960,9 +6126,9 @@ } }, "spdx-license-ids": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", - "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==" + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==" }, "split": { "version": "1.0.1", @@ -5990,7 +6156,7 @@ }, "sprintf-js": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sql-template-strings": { @@ -5999,9 +6165,9 @@ "integrity": "sha1-PxFQiiWt384hejBCqdMAwxk7lv8=" }, "sshpk": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", - "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -6022,9 +6188,9 @@ "dev": true }, "standard-as-callback": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-1.0.1.tgz", - "integrity": "sha512-izxEITSyc7S+5oOiF/URiYaNkemPUxIndCNv66jJ548Y1TVxhBvioNMSPrZIQdaZDlhnguOdUzHA/7hJ3xFhuQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.0.1.tgz", + "integrity": "sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg==" }, "static-extend": { "version": "0.1.2", @@ -6059,33 +6225,49 @@ "requires": { "astral-regex": "^1.0.0", "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "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" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -6098,7 +6280,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -6123,21 +6305,55 @@ "dev": true }, "table": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/table/-/table-5.1.1.tgz", - "integrity": "sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.0.tgz", + "integrity": "sha512-nHFDrxmbrkU7JAFKqKbDJXfzrX2UBsWmrieXFTGxiI5e4ncg3VqsZeI4EzNmX0ncp4XNGVeoxIWJXfCIXwrsvw==", "dev": true, "requires": { - "ajv": "^6.6.1", + "ajv": "^6.9.1", "lodash": "^4.17.11", - "slice-ansi": "2.0.0", - "string-width": "^2.1.1" + "slice-ansi": "^2.1.0", + "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==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, "tarn": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.4.tgz", - "integrity": "sha512-j4samMCQCP5+6Il9/cxCqBd3x4vvlLeVdoyGex0KixPKl4F8LpNbDSC6NDhjianZgUngElRr9UI1ryZqJDhwGg==" + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz", + "integrity": "sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g==" }, "template2env": { "version": "1.0.4", @@ -6262,7 +6478,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { @@ -6405,23 +6621,16 @@ } }, "uglify-js": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", - "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", "dev": true, "optional": true, "requires": { - "commander": "~2.17.1", + "commander": "~2.20.0", "source-map": "~0.6.1" }, "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true, - "optional": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6544,9 +6753,9 @@ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "v8flags": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.1.tgz", - "integrity": "sha512-iw/1ViSEaff8NJ3HLyEjawk/8hjJib3E7pvG4pddVXfUg1983s3VGsiClDjhK64MQVDGqc1Q8r18S4VKQZS9EQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", + "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", "requires": { "homedir-polyfill": "^1.0.1" } @@ -6640,10 +6849,9 @@ } }, "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" }, "window-size": { "version": "0.2.0", @@ -6658,44 +6866,11 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } } }, "wrappy": { @@ -6704,18 +6879,18 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", "dev": true, "requires": { "mkdirp": "^0.5.1" } }, "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -6755,32 +6930,33 @@ "dev": true }, "yargs": { - "version": "11.1.0", - "resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz", + "integrity": "sha1-M1UUSXfQV1fbuG1uOOwFYSOzpm4=", "requires": { - "cliui": "^4.0.0", + "cliui": "^3.2.0", "decamelize": "^1.1.1", - "find-up": "^2.1.0", "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", + "lodash.assign": "^4.2.0", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", "require-directory": "^2.1.1", "require-main-filename": "^1.0.1", "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "window-size": "^0.2.0", "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" + "yargs-parser": "^3.2.0" } }, "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "dev": true, + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz", + "integrity": "sha1-UIE1XRnZ0MjF2BrakIy05tGGZk8=", "requires": { - "camelcase": "^4.1.0" + "camelcase": "^3.0.0", + "lodash.assign": "^4.1.0" } } } From 5f7c084ab22223bb36bab85cd2e1172c9445311a Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Thu, 6 Jun 2019 15:41:22 -0400 Subject: [PATCH 14/24] Add some tests --- redis/lock.js | 35 +++++++++----- redis/lock.test.js | 116 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 redis/lock.test.js diff --git a/redis/lock.js b/redis/lock.js index d2f717c..46758b4 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -1,7 +1,6 @@ 'use strict'; -const Redlock = require('redlock'), - { logGenericError } = require('../services/errors'), +const { logGenericError } = require('../services/errors'), emptyModule = { lock: () => Promise.resolve(), unlock: () => Promise.resolve() @@ -34,6 +33,8 @@ const Redlock = require('redlock'), actionRetryTotal = 5; let log = require('../services/log').setup({ file: __filename }), + Redlock = require('redlock'), + _logGenericError = logGenericError(__filename), actionRetryCount = 0; /** @@ -58,19 +59,20 @@ function addLock(lockName, ttl) { * * @param {Object} lock * @param {string} lockName - * @param {Function} cb Must return a promise + * @param {Function} promise * @returns {Promise} */ -function removeLockWhenReady(lock, lockName, cb) { - return cb().then(result => - module.exports.redlock.unlock(lock).then(() => { +function removeLockWhenReady(lock, lockName, promise) { + return promise().then(result => { + return module.exports.redlock.unlock(lock).then(() => { log('trace', `Releasing lock for resource id ${lockName}`, { lockName, processId: process.pid }); + return result; - }) - ); + }); + }); } /** @@ -163,7 +165,7 @@ function setupRedlock(instance) { const redlock = new Redlock([instance], CONFIG); - redlock.on('clientError', logGenericError(__filename)); + redlock.on('clientError', _logGenericError); module.exports.redis = instance; module.exports.redlock = redlock; @@ -171,8 +173,19 @@ function setupRedlock(instance) { return redlock; } -module.exports.redis = {}; +module.exports.redis; module.exports.redlock; - module.exports.setupRedlock = setupRedlock; module.exports.applyLock = applyLock; + +module.exports.stubRedlockModule = mock => Redlock = mock; +module.exports.stubLogGenericError = mock => _logGenericError = mock; +module.exports.stubLog = mock => log = mock; + +module.exports._addLock = addLock; +module.exports._removeLockWhenReady = removeLockWhenReady; +module.exports._getState = getState; +module.exports._setState = setState; +module.exports._sleepAndRun = sleepAndRun; +module.exports._lockAndExecute = lockAndExecute; +module.exports._retryLocking = retryLocking; diff --git a/redis/lock.test.js b/redis/lock.test.js new file mode 100644 index 0000000..8749b61 --- /dev/null +++ b/redis/lock.test.js @@ -0,0 +1,116 @@ +'use strict'; + +// module.exports._addLock = addLock; +// module.exports._removeLockWhenReady = removeLockWhenReady; +// module.exports._sleepAndRun = sleepAndRun; +// module.exports._lockAndExecute = lockAndExecute; +// module.exports._retryLocking = retryLocking; + +const lockModule = require('./lock'), + REDIS_CLIENT = { + getAsync: jest.fn().mockResolvedValue(), + setAsync: jest.fn().mockResolvedValue(), + expire: jest.fn() + }, + fakeGenericErrorLog = jest.fn(), + fakeLog = jest.fn(), + fakeRedlockInstance = { + unlock: jest.fn() + }, + redlockModule = jest.genMockFromModule('redlock'); + +describe('lock', () => { + beforeEach(() => { + lockModule.stubLogGenericError(fakeGenericErrorLog); + lockModule.stubLog(fakeLog); + lockModule.redlock = fakeRedlockInstance; + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + describe('setupRedlock', () => { + test('Returns redlock instance', () => { + lockModule.stubRedlockModule(redlockModule); + + const redlockClient = lockModule.setupRedlock(REDIS_CLIENT); + + expect(redlockClient).toBeInstanceOf(redlockModule); + expect(redlockClient.on).toHaveBeenCalledWith('clientError', fakeGenericErrorLog); + }); + }); + + describe('getState', () => { + test('It should call redis getAsync', () => { + const key = 'some/key'; + + return lockModule._getState(key) + .then(() => + expect(REDIS_CLIENT.getAsync).toBeCalledWith(key)); + }); + }); + + describe('setState', () => { + const key = 'some/key', + value = 'some/value', + ttl = 2000; + + test('It should call redis setAsync', () => { + return lockModule._setState(key, value) + .then(() => + expect(REDIS_CLIENT.setAsync).toBeCalledWith(key, value)); + }); + + test('It should call redis expire if a TTL is passed', () => { + return lockModule._setState(key, value, ttl) + .then(() => { + expect(REDIS_CLIENT.setAsync).toBeCalledWith(key, value); + expect(REDIS_CLIENT.expire).toBeCalledWith(key, ttl); + }); + }); + }); + + describe('removeLockWhenReady', () => { + const lockName = 'someName', + fakeLock = {}; + + let somePromise; + + beforeEach(() => { + somePromise = jest.fn().mockResolvedValue('callback return value'); + lockModule.redlock.unlock.mockResolvedValue(); + }); + + test('Callback is called', () => { + return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + .then(() => expect(somePromise).toBeCalled()); + }); + + test('Redis unlock is called if callback succeeds', () => { + return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + .then(() => expect(lockModule.redlock.unlock).toBeCalled()); + }); + + test('Redis unlock is not called if callback fails', () => { + somePromise = jest.fn().mockRejectedValue('callback return value'); + + return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + .catch(() => expect(lockModule.redlock.unlock).not.toBeCalled()); + }); + + test('Lock release is logged if unlock succeeds', () => { + return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + .then(() => + expect(fakeLog).toBeCalledWith( + 'trace', + `Releasing lock for resource id ${lockName}`, + { + lockName, + processId: process.pid + } + )); + }); + test('Returns whatever the callback returns', () => { }); + }); +}); \ No newline at end of file From fd5dfdb7f600f0af1262e61361d93a96ace737bc Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Thu, 6 Jun 2019 16:04:54 -0400 Subject: [PATCH 15/24] Add test for the callback return --- redis/lock.test.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/redis/lock.test.js b/redis/lock.test.js index 8749b61..800168c 100644 --- a/redis/lock.test.js +++ b/redis/lock.test.js @@ -73,12 +73,13 @@ describe('lock', () => { describe('removeLockWhenReady', () => { const lockName = 'someName', - fakeLock = {}; + fakeLock = {}, + promiseReturnValue = 'some/value'; let somePromise; beforeEach(() => { - somePromise = jest.fn().mockResolvedValue('callback return value'); + somePromise = jest.fn().mockResolvedValue(promiseReturnValue); lockModule.redlock.unlock.mockResolvedValue(); }); @@ -93,7 +94,7 @@ describe('lock', () => { }); test('Redis unlock is not called if callback fails', () => { - somePromise = jest.fn().mockRejectedValue('callback return value'); + somePromise = jest.fn().mockRejectedValue(); return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) .catch(() => expect(lockModule.redlock.unlock).not.toBeCalled()); @@ -105,12 +106,13 @@ describe('lock', () => { expect(fakeLog).toBeCalledWith( 'trace', `Releasing lock for resource id ${lockName}`, - { - lockName, - processId: process.pid - } + { lockName, processId: process.pid } )); }); - test('Returns whatever the callback returns', () => { }); + + test('Returns whatever the callback returns', () => { + return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + .then(result => expect(result).toBe(promiseReturnValue)); + }); }); }); \ No newline at end of file From c063f99b09a03fbd20a4063c6ff33eb2275fadbb Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Thu, 6 Jun 2019 16:37:56 -0400 Subject: [PATCH 16/24] Add addLock tests --- redis/lock.test.js | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/redis/lock.test.js b/redis/lock.test.js index 800168c..8fec298 100644 --- a/redis/lock.test.js +++ b/redis/lock.test.js @@ -1,7 +1,5 @@ 'use strict'; -// module.exports._addLock = addLock; -// module.exports._removeLockWhenReady = removeLockWhenReady; // module.exports._sleepAndRun = sleepAndRun; // module.exports._lockAndExecute = lockAndExecute; // module.exports._retryLocking = retryLocking; @@ -15,6 +13,7 @@ const lockModule = require('./lock'), fakeGenericErrorLog = jest.fn(), fakeLog = jest.fn(), fakeRedlockInstance = { + lock: jest.fn(), unlock: jest.fn() }, redlockModule = jest.genMockFromModule('redlock'); @@ -115,4 +114,26 @@ describe('lock', () => { .then(result => expect(result).toBe(promiseReturnValue)); }); }); -}); \ No newline at end of file + + describe('addLock', () => { + const lockName = 'some-name', + ttl = 2000; + + test('Should call redlock.lock', () => { + lockModule.redlock.lock.mockResolvedValue(); + + return lockModule._addLock(lockName, ttl).then(() => { + expect(lockModule.redlock.lock).toBeCalledWith(lockName, ttl); + }); + }); + + test('Message is logged when addLock is called', () => { + return lockModule._addLock(lockName, ttl).then(() => + expect(fakeLog).toBeCalledWith( + 'trace', + `Trying to lock redis for resource id ${lockName}`, + { lockName, processId: process.pid } + )); + }); + }); +}); From 755997f2fd88b5843e79851bc0f49ce5ef196bd2 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Thu, 6 Jun 2019 17:02:32 -0400 Subject: [PATCH 17/24] Add test for sleepAndRun --- redis/lock.js | 5 +++-- redis/lock.test.js | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index 46758b4..75da00e 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -1,6 +1,7 @@ 'use strict'; -const { logGenericError } = require('../services/errors'), +const Promise = require('bluebird'), + { logGenericError } = require('../services/errors'), emptyModule = { lock: () => Promise.resolve(), unlock: () => Promise.resolve() @@ -107,7 +108,7 @@ function setState(key, value, expireTime) { * @returns {Promise} */ function sleepAndRun(cb, ms = 1000) { - return new Promise(resolve => setTimeout(() => cb().then(resolve), ms)); + return Promise.delay(ms).then(cb); } /** diff --git a/redis/lock.test.js b/redis/lock.test.js index 8fec298..bebdae6 100644 --- a/redis/lock.test.js +++ b/redis/lock.test.js @@ -136,4 +136,14 @@ describe('lock', () => { )); }); }); + + describe('sleepAndRun', () => { + test('Callback is called', () => { + const somePromise = jest.fn().mockResolvedValue('value'); + + return lockModule._sleepAndRun(somePromise, 250).then(() => { + expect(somePromise).toBeCalled(); + }); + }); + }); }); From 1dd583be41bd172d9b40c6d8ba5f34cd6fa75b43 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Tue, 11 Jun 2019 14:03:28 -0400 Subject: [PATCH 18/24] Add tests for retryLocking --- redis/lock.js | 26 +++++++++++++++----------- redis/lock.test.js | 30 +++++++++++++++++++----------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index 75da00e..b3f12d0 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -30,13 +30,13 @@ const Promise = require('bluebird'), }, RETRY_TIME = 1500, // ms KEY_TTL = 10 * 60, // secs - LOCK_TTL = 5000, // ms - actionRetryTotal = 5; + LOCK_TTL = 5000; // ms let log = require('../services/log').setup({ file: __filename }), Redlock = require('redlock'), _logGenericError = logGenericError(__filename), - actionRetryCount = 0; + actionRetryCount = 0, + actionRetryTotal = 5; /** * Adds a lock to redis with the given lockName @@ -103,12 +103,11 @@ function setState(key, value, expireTime) { /** * Waits an amount of time, then runs the callback * - * @param {Function} cb * @param {number} ms * @returns {Promise} */ -function sleepAndRun(cb, ms = 1000) { - return Promise.delay(ms).then(cb); +function delay(ms = RETRY_TIME) { + return Promise.delay(ms); } /** @@ -121,12 +120,15 @@ function applyLock(action, cb) { const lockName = `${action}-lock`; return getState(action).then(state => { + if (state === STATE.FINISHED) return; + /** * If it's ONGOING, just re-run this function after a while * to see if the state changed. */ if (state === STATE.ONGOING) { - return sleepAndRun(() => applyLock(action, cb), RETRY_TIME); + return delay() + .then(() => applyLock(action, cb)); } if (!state || state === STATE.RETRY) @@ -151,7 +153,8 @@ function retryLocking(action, cb) { } return setState(action, STATE.RETRY) - .then(() => sleepAndRun(() => applyLock(action, cb), RETRY_TIME)); + .then(delay) + .then(() => applyLock(action, cb)); } /** @@ -182,11 +185,12 @@ module.exports.applyLock = applyLock; module.exports.stubRedlockModule = mock => Redlock = mock; module.exports.stubLogGenericError = mock => _logGenericError = mock; module.exports.stubLog = mock => log = mock; +module.exports.stubActionRetryTotal = mock => actionRetryTotal = mock; module.exports._addLock = addLock; module.exports._removeLockWhenReady = removeLockWhenReady; -module.exports._getState = getState; -module.exports._setState = setState; -module.exports._sleepAndRun = sleepAndRun; +module.exports.getState = getState; +module.exports.setState = setState; +module.exports.delay = delay; module.exports._lockAndExecute = lockAndExecute; module.exports._retryLocking = retryLocking; diff --git a/redis/lock.test.js b/redis/lock.test.js index bebdae6..d480894 100644 --- a/redis/lock.test.js +++ b/redis/lock.test.js @@ -1,6 +1,5 @@ 'use strict'; -// module.exports._sleepAndRun = sleepAndRun; // module.exports._lockAndExecute = lockAndExecute; // module.exports._retryLocking = retryLocking; @@ -13,8 +12,8 @@ const lockModule = require('./lock'), fakeGenericErrorLog = jest.fn(), fakeLog = jest.fn(), fakeRedlockInstance = { - lock: jest.fn(), - unlock: jest.fn() + lock: jest.fn().mockResolvedValue(), + unlock: jest.fn().mockResolvedValue() }, redlockModule = jest.genMockFromModule('redlock'); @@ -23,6 +22,7 @@ describe('lock', () => { lockModule.stubLogGenericError(fakeGenericErrorLog); lockModule.stubLog(fakeLog); lockModule.redlock = fakeRedlockInstance; + lockModule.redis = REDIS_CLIENT; }); afterEach(() => { @@ -44,7 +44,7 @@ describe('lock', () => { test('It should call redis getAsync', () => { const key = 'some/key'; - return lockModule._getState(key) + return lockModule.getState(key) .then(() => expect(REDIS_CLIENT.getAsync).toBeCalledWith(key)); }); @@ -56,13 +56,13 @@ describe('lock', () => { ttl = 2000; test('It should call redis setAsync', () => { - return lockModule._setState(key, value) + return lockModule.setState(key, value) .then(() => expect(REDIS_CLIENT.setAsync).toBeCalledWith(key, value)); }); test('It should call redis expire if a TTL is passed', () => { - return lockModule._setState(key, value, ttl) + return lockModule.setState(key, value, ttl) .then(() => { expect(REDIS_CLIENT.setAsync).toBeCalledWith(key, value); expect(REDIS_CLIENT.expire).toBeCalledWith(key, ttl); @@ -137,12 +137,20 @@ describe('lock', () => { }); }); - describe('sleepAndRun', () => { - test('Callback is called', () => { - const somePromise = jest.fn().mockResolvedValue('value'); + describe('retryLocking', () => { + const action = 'some-action', + callback = jest.fn().mockResolvedValue(); + + test('Sets the state to RETRY if the retries are not over', () => { + return lockModule._retryLocking(action, callback).then(() => { + expect(REDIS_CLIENT.setAsync.mock.calls[0][1]).toBe('RETRY'); + }); + }); - return lockModule._sleepAndRun(somePromise, 250).then(() => { - expect(somePromise).toBeCalled(); + test('Sets the state to FINISHED if the retries are over', () => { + lockModule.stubActionRetryTotal(2); + return lockModule._retryLocking(action, callback).then(() => { + expect(REDIS_CLIENT.setAsync.mock.calls[0][1]).toBe('FINISHED'); }); }); }); From 0f35cb5ad886ed9222e5c414914742a17aa23f22 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Tue, 11 Jun 2019 14:25:57 -0400 Subject: [PATCH 19/24] Add tests for lockAndExecute --- redis/lock.js | 8 +++---- redis/lock.test.js | 54 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index b3f12d0..3505312 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -187,10 +187,10 @@ module.exports.stubLogGenericError = mock => _logGenericError = mock; module.exports.stubLog = mock => log = mock; module.exports.stubActionRetryTotal = mock => actionRetryTotal = mock; -module.exports._addLock = addLock; -module.exports._removeLockWhenReady = removeLockWhenReady; +module.exports.addLock = addLock; +module.exports.removeLockWhenReady = removeLockWhenReady; module.exports.getState = getState; module.exports.setState = setState; module.exports.delay = delay; -module.exports._lockAndExecute = lockAndExecute; -module.exports._retryLocking = retryLocking; +module.exports.lockAndExecute = lockAndExecute; +module.exports.retryLocking = retryLocking; diff --git a/redis/lock.test.js b/redis/lock.test.js index d480894..127853b 100644 --- a/redis/lock.test.js +++ b/redis/lock.test.js @@ -1,8 +1,5 @@ 'use strict'; -// module.exports._lockAndExecute = lockAndExecute; -// module.exports._retryLocking = retryLocking; - const lockModule = require('./lock'), REDIS_CLIENT = { getAsync: jest.fn().mockResolvedValue(), @@ -83,24 +80,24 @@ describe('lock', () => { }); test('Callback is called', () => { - return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + return lockModule.removeLockWhenReady(fakeLock, lockName, somePromise) .then(() => expect(somePromise).toBeCalled()); }); test('Redis unlock is called if callback succeeds', () => { - return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + return lockModule.removeLockWhenReady(fakeLock, lockName, somePromise) .then(() => expect(lockModule.redlock.unlock).toBeCalled()); }); test('Redis unlock is not called if callback fails', () => { somePromise = jest.fn().mockRejectedValue(); - return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + return lockModule.removeLockWhenReady(fakeLock, lockName, somePromise) .catch(() => expect(lockModule.redlock.unlock).not.toBeCalled()); }); test('Lock release is logged if unlock succeeds', () => { - return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + return lockModule.removeLockWhenReady(fakeLock, lockName, somePromise) .then(() => expect(fakeLog).toBeCalledWith( 'trace', @@ -110,7 +107,7 @@ describe('lock', () => { }); test('Returns whatever the callback returns', () => { - return lockModule._removeLockWhenReady(fakeLock, lockName, somePromise) + return lockModule.removeLockWhenReady(fakeLock, lockName, somePromise) .then(result => expect(result).toBe(promiseReturnValue)); }); }); @@ -122,13 +119,13 @@ describe('lock', () => { test('Should call redlock.lock', () => { lockModule.redlock.lock.mockResolvedValue(); - return lockModule._addLock(lockName, ttl).then(() => { + return lockModule.addLock(lockName, ttl).then(() => { expect(lockModule.redlock.lock).toBeCalledWith(lockName, ttl); }); }); test('Message is logged when addLock is called', () => { - return lockModule._addLock(lockName, ttl).then(() => + return lockModule.addLock(lockName, ttl).then(() => expect(fakeLog).toBeCalledWith( 'trace', `Trying to lock redis for resource id ${lockName}`, @@ -142,16 +139,49 @@ describe('lock', () => { callback = jest.fn().mockResolvedValue(); test('Sets the state to RETRY if the retries are not over', () => { - return lockModule._retryLocking(action, callback).then(() => { + return lockModule.retryLocking(action, callback).then(() => { expect(REDIS_CLIENT.setAsync.mock.calls[0][1]).toBe('RETRY'); }); }); test('Sets the state to FINISHED if the retries are over', () => { lockModule.stubActionRetryTotal(2); - return lockModule._retryLocking(action, callback).then(() => { + return lockModule.retryLocking(action, callback).then(() => { expect(REDIS_CLIENT.setAsync.mock.calls[0][1]).toBe('FINISHED'); }); }); }); + + describe('lockAndExecute', () => { + const action = 'some-action', + lockName = 'some-action-lock', + somePromise = jest.fn().mockResolvedValue(); + + test('Sets the state to ongoing', () => { + return lockModule.lockAndExecute(action, lockName, somePromise).then(() => { + expect(REDIS_CLIENT.setAsync.mock.calls[0][1]).toBe('ON-GOING'); + }); + }); + + test('Adds the lock', () => { + return lockModule.lockAndExecute(action, lockName, somePromise).then(() => { + expect(fakeRedlockInstance.lock.mock.calls[0][0]).toBe(lockName); + }); + }); + + test('Removes the lock', () => { + const someLock = { name: 'lock-name' }; + + fakeRedlockInstance.lock.mockResolvedValue(someLock); + return lockModule.lockAndExecute(action, lockName, somePromise).then(() => { + expect(fakeRedlockInstance.unlock.mock.calls[0][0]).toBe(someLock); + }); + }); + + test('Sets the stage to finished with a TTL if everything succeeds', () => { + return lockModule.lockAndExecute(action, lockName, somePromise).then(() => { + expect(REDIS_CLIENT.setAsync.mock.calls[1][1]).toBe('FINISHED'); + }); + }); + }); }); From d5225933960097f9ae2595481130276db5376ae5 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Tue, 11 Jun 2019 14:41:23 -0400 Subject: [PATCH 20/24] Remove validation --- redis/lock.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index 3505312..71ecb21 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -2,10 +2,6 @@ const Promise = require('bluebird'), { logGenericError } = require('../services/errors'), - emptyModule = { - lock: () => Promise.resolve(), - unlock: () => Promise.resolve() - }, CONFIG = { // the expected clock drift; for more details // see http://redis.io/topics/distlock @@ -165,8 +161,6 @@ function retryLocking(action, cb) { * @returns {Object} Redlock instance */ function setupRedlock(instance) { - if (!instance) return emptyModule; - const redlock = new Redlock([instance], CONFIG); redlock.on('clientError', _logGenericError); From d87114eb690d193a77ac593aecb99cc50582c1ff Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Tue, 11 Jun 2019 16:37:02 -0400 Subject: [PATCH 21/24] Add tests for applyLock --- redis/lock.js | 7 ++++--- redis/lock.test.js | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index 71ecb21..7d4a06e 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -1,7 +1,6 @@ 'use strict'; -const Promise = require('bluebird'), - { logGenericError } = require('../services/errors'), +const { logGenericError } = require('../services/errors'), CONFIG = { // the expected clock drift; for more details // see http://redis.io/topics/distlock @@ -30,6 +29,7 @@ const Promise = require('bluebird'), let log = require('../services/log').setup({ file: __filename }), Redlock = require('redlock'), + Promise = require('bluebird'), _logGenericError = logGenericError(__filename), actionRetryCount = 0, actionRetryTotal = 5; @@ -97,7 +97,7 @@ function setState(key, value, expireTime) { } /** - * Waits an amount of time, then runs the callback + * Waits an amount of time * * @param {number} ms * @returns {Promise} @@ -180,6 +180,7 @@ module.exports.stubRedlockModule = mock => Redlock = mock; module.exports.stubLogGenericError = mock => _logGenericError = mock; module.exports.stubLog = mock => log = mock; module.exports.stubActionRetryTotal = mock => actionRetryTotal = mock; +module.exports.stubBluebirdModule = mock => Promise = mock; module.exports.addLock = addLock; module.exports.removeLockWhenReady = removeLockWhenReady; diff --git a/redis/lock.test.js b/redis/lock.test.js index 127853b..9b2ad34 100644 --- a/redis/lock.test.js +++ b/redis/lock.test.js @@ -12,12 +12,17 @@ const lockModule = require('./lock'), lock: jest.fn().mockResolvedValue(), unlock: jest.fn().mockResolvedValue() }, - redlockModule = jest.genMockFromModule('redlock'); + redlockModule = jest.genMockFromModule('redlock'), + bluebirdModule = { + delay: jest.fn().mockResolvedValue() + }; -describe('lock', () => { +describe('redis/lock', () => { beforeEach(() => { + lockModule.stubActionRetryTotal(5); lockModule.stubLogGenericError(fakeGenericErrorLog); lockModule.stubLog(fakeLog); + lockModule.stubBluebirdModule(bluebirdModule); lockModule.redlock = fakeRedlockInstance; lockModule.redis = REDIS_CLIENT; }); @@ -184,4 +189,36 @@ describe('lock', () => { }); }); }); + + describe('applyLock', () => { + const action = 'some-action', + callback = jest.fn().mockResolvedValue(); + + test('When state is ONGOING, it should call delay', () => { + REDIS_CLIENT.getAsync.mockResolvedValueOnce('ON-GOING'); + REDIS_CLIENT.getAsync.mockResolvedValueOnce('FINISHED'); + + return lockModule.applyLock(action, callback).then(() => { + expect(bluebirdModule.delay).toBeCalledWith(1500); + }); + }); + + test.each([undefined, 'RETRY'])('It should call retryLocking when state is %s and lockAndExecute fails', state => { + REDIS_CLIENT.getAsync.mockResolvedValueOnce(state); + REDIS_CLIENT.setAsync.mockRejectedValue('Not found'); + + return lockModule.applyLock(action, callback).catch(() => { + expect(REDIS_CLIENT.setAsync).toBeCalledWith(action, 'RETRY'); + }); + }); + + test('It should not run anything if the state has an unknown value', () => { + REDIS_CLIENT.getAsync.mockResolvedValueOnce('some-random-state'); + + return lockModule.applyLock(action, callback).then(() => { + expect(REDIS_CLIENT.setAsync).not.toBeCalled(); + expect(REDIS_CLIENT.getAsync).toBeCalledTimes(1); + }); + }); + }); }); From dc826e0142ae291778d22bf44e32760d71c888c9 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Tue, 11 Jun 2019 16:51:39 -0400 Subject: [PATCH 22/24] Add some JSDocs --- redis/lock.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/redis/lock.js b/redis/lock.js index 7d4a06e..53fa27f 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -107,6 +107,14 @@ function delay(ms = RETRY_TIME) { } /** + * Implements the lock on redis. + * Delays further retries while the + * callback is running. + * + * If something fails, it tries to + * apply the lock again for a certain + * amount of times. + * * * @param {string} action * @param {Function} cb @@ -133,6 +141,15 @@ function applyLock(action, cb) { }); } +/** + * Sets the lock on redis and removes it + * when the callback is done + * + * @param {string} action + * @param {string} lockName + * @param {Function} cb + * @returns {Promise} + */ function lockAndExecute(action, lockName, cb) { return setState(action, STATE.ONGOING) .then(() => addLock(lockName, LOCK_TTL)) @@ -140,6 +157,15 @@ function lockAndExecute(action, lockName, cb) { .then(() => setState(action, STATE.FINISHED, KEY_TTL)); } +/** + * Sets the state to RETRY and runs the lock again. + * After a number of retries, it gives up and sets the + * state to FINISHED. + * + * @param {string} action + * @param {Function} cb + * @returns {Promise} + */ function retryLocking(action, cb) { actionRetryCount++; From 9c9623c7eb372f6144a30bebb007df8655ab79e9 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Tue, 11 Jun 2019 16:51:57 -0400 Subject: [PATCH 23/24] Remove empty line --- redis/lock.js | 1 - 1 file changed, 1 deletion(-) diff --git a/redis/lock.js b/redis/lock.js index 53fa27f..790b91c 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -115,7 +115,6 @@ function delay(ms = RETRY_TIME) { * apply the lock again for a certain * amount of times. * - * * @param {string} action * @param {Function} cb * @returns {Promise} From ba43228179d32f9cfe1bc705c855b9ba5811b054 Mon Sep 17 00:00:00 2001 From: Pedro Rosario Date: Wed, 12 Jun 2019 15:11:39 -0400 Subject: [PATCH 24/24] Change bluebird name and improve test --- redis/lock.js | 7 +++---- redis/lock.test.js | 9 ++++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/redis/lock.js b/redis/lock.js index 790b91c..efbad36 100644 --- a/redis/lock.js +++ b/redis/lock.js @@ -1,6 +1,7 @@ 'use strict'; -const { logGenericError } = require('../services/errors'), +const bluebird = require('bluebird'), + { logGenericError } = require('../services/errors'), CONFIG = { // the expected clock drift; for more details // see http://redis.io/topics/distlock @@ -29,7 +30,6 @@ const { logGenericError } = require('../services/errors'), let log = require('../services/log').setup({ file: __filename }), Redlock = require('redlock'), - Promise = require('bluebird'), _logGenericError = logGenericError(__filename), actionRetryCount = 0, actionRetryTotal = 5; @@ -103,7 +103,7 @@ function setState(key, value, expireTime) { * @returns {Promise} */ function delay(ms = RETRY_TIME) { - return Promise.delay(ms); + return bluebird.delay(ms); } /** @@ -205,7 +205,6 @@ module.exports.stubRedlockModule = mock => Redlock = mock; module.exports.stubLogGenericError = mock => _logGenericError = mock; module.exports.stubLog = mock => log = mock; module.exports.stubActionRetryTotal = mock => actionRetryTotal = mock; -module.exports.stubBluebirdModule = mock => Promise = mock; module.exports.addLock = addLock; module.exports.removeLockWhenReady = removeLockWhenReady; diff --git a/redis/lock.test.js b/redis/lock.test.js index 9b2ad34..96eb3ed 100644 --- a/redis/lock.test.js +++ b/redis/lock.test.js @@ -13,16 +13,15 @@ const lockModule = require('./lock'), unlock: jest.fn().mockResolvedValue() }, redlockModule = jest.genMockFromModule('redlock'), - bluebirdModule = { - delay: jest.fn().mockResolvedValue() - }; + bluebird = require('bluebird'); + +bluebird.delay = jest.fn().mockResolvedValue(); describe('redis/lock', () => { beforeEach(() => { lockModule.stubActionRetryTotal(5); lockModule.stubLogGenericError(fakeGenericErrorLog); lockModule.stubLog(fakeLog); - lockModule.stubBluebirdModule(bluebirdModule); lockModule.redlock = fakeRedlockInstance; lockModule.redis = REDIS_CLIENT; }); @@ -199,7 +198,7 @@ describe('redis/lock', () => { REDIS_CLIENT.getAsync.mockResolvedValueOnce('FINISHED'); return lockModule.applyLock(action, callback).then(() => { - expect(bluebirdModule.delay).toBeCalledWith(1500); + expect(bluebird.delay).toBeCalledWith(1500); }); });