diff --git a/bin/cli b/bin/cli index c0690e455..7e27fa85b 100755 --- a/bin/cli +++ b/bin/cli @@ -13,6 +13,7 @@ program .command('setup', 'setup the application') .command('jobs', 'work with the job queues') .command('users', 'work with the application auth') + .command('plugins', 'provides utilities for interacting with the plugin system') .parse(process.argv); /** diff --git a/bin/cli-plugins b/bin/cli-plugins new file mode 100755 index 000000000..581631573 --- /dev/null +++ b/bin/cli-plugins @@ -0,0 +1,193 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +const program = require('./commander'); + +// Make things colorful! +require('colors'); + +const fs = require('fs'); +const path = require('path'); +const spawn = require('cross-spawn'); +const resolve = require('resolve'); +const {plugins, isInternal} = require('../plugins'); + +function existsInNodeModules(name) { + try { + resolve.sync(name, {basedir: process.cwd()}); + + return true; + } catch (e) { + return false; + } +} + +const EXTERNAL = /^\w[a-z\-0-9\.]+$/; // Match "react", "path", "fs", "lodash.random", etc. + +async function reconcileRemotePlugins(dryRun) { + const linkable = []; + const fetchable = []; + + console.log('\n[1/3] 🔍 Reconciling plugins...\n'.yellow); + console.log(' +local (l) packages in your project\n +external (e) referenced packages in node_modules but not in current project\n +missing (m) referenced packages but not found\n +symlinked (sl) symlinked external packages\n'); + for (let i in plugins) { + let section = plugins[i]; + + for (let name in section) { + let version = section[name]; + + let namespaced = name.charAt(0) === '@'; + let dep = name.split('/') + .slice(0, namespaced ? 2 : 1) + .join('/'); + + // Ignore relative modules, which aren't installed by NPM + if (!dep.match(EXTERNAL) && !namespaced) { + return; + } + + if (isInternal(dep)) { + let stat = fs.lstatSync(path.join(process.cwd(), 'plugins', name)); + if (stat.isSymbolicLink()) { + console.log(` sl ${name.cyan}`); + } else { + console.log(` l ${name.cyan}`); + } + + continue; + } + + if (!existsInNodeModules(dep)) { + console.warn(` m ${name.cyan}`); + fetchable.push({name, version}); + } else { + console.log(` e ${name.cyan}`); + linkable.push({name, version}); + } + } + } + + console.log('\n[2/3] 🚚 Fetching plugins...\n'.yellow); + + if (fetchable.length > 0) { + + console.log(`$ yarn add ${fetchable.map(({name, version}) => `${name}@${version}`.cyan)}`); + + if (!dryRun) { + + let args = [ + 'add', + ...fetchable.map(({name, version}) => `${name}@${version}`) + ]; + + let output = spawn.sync('yarn', args, { + stdio: ['ignore', 'pipe', 'inherit'] + }); + + if (output.status) { + throw new Error('Could not install external plugins, errors occured during install'); + } + + console.log(output.stdout.toString()); + } + + fetchable.forEach((plugin) => { + linkable.push(plugin); + }); + } + + // TODO fetch the plugins using yarn + + console.log('\n[3/3] 🔗 Linking plugins...\n'.yellow); + + for (let i in linkable) { + let {name} = linkable[i]; + + let src = path.join(process.cwd(), 'node_modules', name); + let dst = path.join(process.cwd(), 'plugins', name); + + console.log(`$ link ${src.cyan} -> ${dst.cyan}`); + + if (!dryRun) { + + // Create the symlink for the plugin directory. + fs.symlinkSync(src, dst, 'dir'); + } + } + + return {linkable, fetchable}; +} + +// This traverses the local plugins and installs any dependencies listed there, +// this only is really needed for plugins that are installed via docker because +// core plugins will have their dependencies already included in core. +async function reconcilePluginDeps(options) { + let startTime = new Date(); + + // We don't need to do anything if we skip everything.... + if (options.skipLocal && options.skipRemote) { + return; + } + + // Traverse local plugins and install dependencies if enabled. + if (!options.skipLocal) { + + } + + // Locate any external plugins and install them. + if (!options.skipRemote) { + let results = []; + try { + results = await reconcileRemotePlugins(options.dryRun); + } catch (e) { + throw e; + } + + let status; + if (options.dryRun) { + status = '[dry-run] success'.green; + } else { + status = 'success'.green; + } + + let message; + if (results.linkable.length === 0 && results.fetchable.length === 0) { + message = 'Already up-to-date.'; + } else if (results.linkable.length === 0) { + message = `Fetched ${results.fetchable.length} new plugins.`; + } else if (results.fetchable.length === 0) { + message = `Linked ${results.linkable.length} new plugins.`; + } else { + message = `Fetched ${results.fetchable.length} new plugins, linked ${results.linkable.length} plugins.`; + } + + console.log(`\n${status} ${message}`); + } + + let endTime = new Date(); + + let totalTime = ((endTime.getTime() - startTime.getTime()) / 1000).toFixed(2); + console.log(`✨ Done in ${totalTime}s.`); +} + +//============================================================================== +// Setting up the program command line arguments. +//============================================================================== + +program + .command('reconcile') + .description('reconciles local plugin dependencies and downloads external plugins') + .option('-d, --dry-run', 'does not actually change anything on the filesystem acts only as a simulation') + .option('--skip-local', 'skips the local dependancy reconciliation') + .option('--skip-remote', 'skips the remote plugin reconciliation') + .action(reconcilePluginDeps); + +program.parse(process.argv); + +// If there is no command listed, output help. +if (!process.argv.slice(2).length) { + program.outputHelp(); +} diff --git a/graph/context.js b/graph/context.js index 432ab2081..f3ed42ad8 100644 --- a/graph/context.js +++ b/graph/context.js @@ -1,7 +1,7 @@ const loaders = require('./loaders'); const mutators = require('./mutators'); -const plugins = require('../plugins'); +const plugins = require('../services/plugins'); const debug = require('debug')('talk:graph:context'); /** diff --git a/graph/loaders/index.js b/graph/loaders/index.js index 40e723918..26727940f 100644 --- a/graph/loaders/index.js +++ b/graph/loaders/index.js @@ -8,7 +8,7 @@ const Metrics = require('./metrics'); const Settings = require('./settings'); const Users = require('./users'); -const plugins = require('../../plugins'); +const plugins = require('../../services/plugins'); let loaders = [ diff --git a/graph/mutators/index.js b/graph/mutators/index.js index e3df4aefb..9975bedde 100644 --- a/graph/mutators/index.js +++ b/graph/mutators/index.js @@ -5,7 +5,7 @@ const Comment = require('./comment'); const Action = require('./action'); const User = require('./user'); -const plugins = require('../../plugins'); +const plugins = require('../../services/plugins'); let mutators = [ diff --git a/graph/resolvers/index.js b/graph/resolvers/index.js index 7e165f2db..361cfa48f 100644 --- a/graph/resolvers/index.js +++ b/graph/resolvers/index.js @@ -20,7 +20,7 @@ const UserError = require('./user_error'); const User = require('./user'); const ValidationUserError = require('./validation_user_error'); -const plugins = require('../../plugins'); +const plugins = require('../../services/plugins'); // Provide the core resolvers. let resolvers = { diff --git a/graph/schema.js b/graph/schema.js index c927d8c32..53360e701 100644 --- a/graph/schema.js +++ b/graph/schema.js @@ -2,7 +2,7 @@ const {makeExecutableSchema} = require('graphql-tools'); const {maskErrors} = require('graphql-errors'); const {decorateWithHooks} = require('./hooks'); -const plugins = require('../plugins'); +const plugins = require('../services/plugins'); const resolvers = require('./resolvers'); const typeDefs = require('./typeDefs'); diff --git a/graph/typeDefs.js b/graph/typeDefs.js index 5b07d0f2d..9b2c8b7aa 100644 --- a/graph/typeDefs.js +++ b/graph/typeDefs.js @@ -6,7 +6,7 @@ const fs = require('fs'); const path = require('path'); const {mergeStrings} = require('gql-merge'); const debug = require('debug')('talk:graph:typeDefs'); -const plugins = require('../plugins'); +const plugins = require('../services/plugins'); /** * Plugin support requires us to merge the type definitions from the loaded diff --git a/package.json b/package.json index 6fdf4560a..17dabb747 100644 --- a/package.json +++ b/package.json @@ -52,8 +52,10 @@ "bcrypt": "^1.0.2", "body-parser": "^1.17.1", "cli-table": "^0.3.1", + "colors": "^1.1.2", "commander": "^2.9.0", "connect-redis": "^3.1.0", + "cross-spawn": "^5.1.0", "csurf": "^1.9.0", "dataloader": "^1.3.0", "debug": "^2.6.3", @@ -88,6 +90,7 @@ "react-apollo": "^0.10.0", "react-recaptcha": "^2.2.6", "redis": "^2.7.1", + "resolve": "^1.3.2", "uuid": "^2.0.3" }, "devDependencies": { diff --git a/plugins.js b/plugins.js index 7713e0b8f..116e9093c 100644 --- a/plugins.js +++ b/plugins.js @@ -1,5 +1,6 @@ const fs = require('fs'); const path = require('path'); +const debug = require('debug')('talk:plugins'); let plugins = {}; @@ -16,13 +17,65 @@ try { } } +/** + * isInternal checks to see if a given plugin is internal, and returns true + * if it is. + * + * @param {String} name + * @returns {Boolean} + */ +function isInternal(name) { + const internalPluginPath = path.join(__dirname, 'plugins', name); + + // Check to see if this plugin exists internally, because if it doesn't, it is + // external. + return fs.existsSync(internalPluginPath); +} + +/** + * Returns the plugin path for the given plugin name. + * + * @param {any} name + * @returns + */ +function pluginPath(name) { + if (isInternal(name)) { + return path.join(__dirname, 'plugins', name); + } + + // The plugin is not available. + return undefined; +} + /** * Stores a reference to a section for a section of Plugins. */ class PluginSection { constructor(plugin_names) { - this.plugins = plugin_names.map((plugin_name) => { - let plugin = require(`./plugins/${plugin_name}`); + this.plugins = Object.keys(plugin_names).map((plugin_name) => { + let plugin = {}; + + // Get the version/folder that was specified. + plugin.version = plugin_names[plugin_name]; + + // Get the path for the plugin. + plugin.path = pluginPath(plugin_name); + + if (typeof plugin.path === 'undefined') { + throw new Error(`plugin '${plugin_name}' is not local or is not symlinked from your node_modules directory, plugin reconsiliation may be required`); + } + + try { + plugin.module = require(plugin.path); + } catch (e) { + throw new Error(`plugin '${plugin_name}' could not be required from '${plugin.path}': ${e.message}`); + } + + if (isInternal(plugin_name)) { + debug(`loading internal plugin '${plugin_name}' from '${plugin.path}'`); + } else { + debug(`loading external plugin '${plugin_name}' from '${plugin.path}'`); + } // Ensure we have a default plugin name, but allow the name to be // overrided by the plugin. @@ -38,8 +91,8 @@ class PluginSection { */ hook(hook) { return this.plugins - .filter((plugin) => hook in plugin) - .map((plugin) => ({plugin, [hook]: plugin[hook]})); + .filter(({module}) => hook in module) + .map((plugin) => ({plugin, [hook]: module[hook]})); } } @@ -78,4 +131,9 @@ class PluginManager { } } -module.exports = new PluginManager(plugins); +module.exports = { + plugins, + PluginManager, + isInternal, + pluginPath +}; diff --git a/services/plugins.js b/services/plugins.js new file mode 100644 index 000000000..ced4bd75a --- /dev/null +++ b/services/plugins.js @@ -0,0 +1,3 @@ +const {plugins, PluginManager} = require('../plugins'); + +module.exports = new PluginManager(plugins); diff --git a/yarn.lock b/yarn.lock index 81ddf18b4..49a633adb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -397,19 +397,7 @@ babel-eslint@^7.2.1: babel-types "^6.23.0" babylon "^6.16.1" -babel-generator@^6.18.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.22.0.tgz#d642bf4961911a8adc7c692b0c9297f325cda805" - dependencies: - babel-messages "^6.22.0" - babel-runtime "^6.22.0" - babel-types "^6.22.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.2.0" - source-map "^0.5.0" - -babel-generator@^6.24.0: +babel-generator@^6.18.0, babel-generator@^6.24.0: version "6.24.0" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56" dependencies: @@ -482,17 +470,7 @@ babel-helper-explode-class@^6.22.0: babel-traverse "^6.22.0" babel-types "^6.22.0" -babel-helper-function-name@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.22.0.tgz#51f1bdc4bb89b15f57a9b249f33d742816dcbefc" - dependencies: - babel-helper-get-function-arity "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" - -babel-helper-function-name@^6.23.0: +babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz#25742d67175c8903dbe4b6cb9d9e1fcb8dcf23a6" dependencies: @@ -576,13 +554,7 @@ babel-loader@^6.4.1: mkdirp "^0.5.1" object-assign "^4.0.1" -babel-messages@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.22.0.tgz#36066a214f1217e4ed4164867669ecb39e3ea575" - dependencies: - babel-runtime "^6.22.0" - -babel-messages@^6.23.0: +babel-messages@^6.22.0, babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" dependencies: @@ -686,16 +658,7 @@ babel-plugin-transform-class-constructor-call@^6.22.0: babel-runtime "^6.22.0" babel-template "^6.22.0" -babel-plugin-transform-class-properties@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.22.0.tgz#aa78f8134495c7de06c097118ba061844e1dc1d8" - dependencies: - babel-helper-function-name "^6.22.0" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.22.0" - babel-template "^6.22.0" - -babel-plugin-transform-class-properties@^6.23.0: +babel-plugin-transform-class-properties@^6.22.0, babel-plugin-transform-class-properties@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.23.0.tgz#187b747ee404399013563c993db038f34754ac3b" dependencies: @@ -925,14 +888,7 @@ babel-plugin-transform-object-assign@^6.8.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-object-rest-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.22.0.tgz#1d419b55e68d2e4f64a5ff3373bd67d73c8e83bc" - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-object-rest-spread@^6.23.0: +babel-plugin-transform-object-rest-spread@^6.22.0, babel-plugin-transform-object-rest-spread@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921" dependencies: @@ -1057,17 +1013,7 @@ babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtim core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.3.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.22.0.tgz#403d110905a4626b317a2a1fcb8f3b73204b2edb" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" - babylon "^6.11.0" - lodash "^4.2.0" - -babel-template@^6.23.0: +babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.23.0, babel-template@^6.3.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638" dependencies: @@ -1077,21 +1023,7 @@ babel-template@^6.23.0: babylon "^6.11.0" lodash "^4.2.0" -babel-traverse@^6.18.0, babel-traverse@^6.22.0: - version "6.22.1" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.22.1.tgz#3b95cd6b7427d6f1f757704908f2fc9748a5f59f" - dependencies: - babel-code-frame "^6.22.0" - babel-messages "^6.22.0" - babel-runtime "^6.22.0" - babel-types "^6.22.0" - babylon "^6.15.0" - debug "^2.2.0" - globals "^9.0.0" - invariant "^2.2.0" - lodash "^4.2.0" - -babel-traverse@^6.23.0, babel-traverse@^6.23.1: +babel-traverse@^6.18.0, babel-traverse@^6.22.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1: version "6.23.1" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48" dependencies: @@ -1105,16 +1037,7 @@ babel-traverse@^6.23.0, babel-traverse@^6.23.1: invariant "^2.2.0" lodash "^4.2.0" -babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.22.0.tgz#2a447e8d0ea25d2512409e4175479fd78cc8b1db" - dependencies: - babel-runtime "^6.22.0" - esutils "^2.0.2" - lodash "^4.2.0" - to-fast-properties "^1.0.1" - -babel-types@^6.23.0: +babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf" dependencies: @@ -1123,11 +1046,11 @@ babel-types@^6.23.0: lodash "^4.2.0" to-fast-properties "^1.0.1" -babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0: +babylon@^6.11.0: version "6.15.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" -babylon@^6.16.1: +babylon@^6.13.0, babylon@^6.15.0, babylon@^6.16.1: version "6.16.1" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3" @@ -1221,22 +1144,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.6" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" -body-parser@^1.12.2: - version "1.16.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.16.0.tgz#924a5e472c6229fb9d69b85a20d5f2532dec788b" - dependencies: - bytes "2.4.0" - content-type "~1.0.2" - debug "2.6.0" - depd "~1.1.0" - http-errors "~1.5.1" - iconv-lite "0.4.15" - on-finished "~2.3.0" - qs "6.2.1" - raw-body "~2.2.0" - type-is "~1.6.14" - -body-parser@^1.17.1: +body-parser@^1.12.2, body-parser@^1.17.1: version "1.17.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" dependencies: @@ -1723,7 +1631,7 @@ colors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" -colors@1.1.2, colors@~1.1.2: +colors@1.1.2, colors@^1.1.2, colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -1965,6 +1873,14 @@ create-hmac@^1.1.0, create-hmac@^1.1.2: create-hash "^1.1.0" inherits "^2.0.1" +cross-spawn@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + crypt@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" @@ -2186,9 +2102,9 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@*, debug@2, debug@2.6.0, debug@^2.1.1, debug@^2.2.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" +debug@*, debug@2, debug@2.6.3, debug@^2.1.1, debug@^2.2.0, debug@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" dependencies: ms "0.7.2" @@ -2210,12 +2126,6 @@ debug@2.6.1: dependencies: ms "0.7.2" -debug@2.6.3, debug@^2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" - dependencies: - ms "0.7.2" - debug@^0.7.2, debug@~0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" @@ -2797,10 +2707,6 @@ esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -etag@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" - etag@~1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" @@ -2871,38 +2777,7 @@ express-session@^1.15.1: uid-safe "~2.1.3" utils-merge "1.0.0" -express@^4.12.2: - version "4.14.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.14.1.tgz#646c237f766f148c2120aff073817b9e4d7e0d33" - dependencies: - accepts "~1.3.3" - array-flatten "1.1.1" - content-disposition "0.5.2" - content-type "~1.0.2" - cookie "0.3.1" - cookie-signature "1.0.6" - debug "~2.2.0" - depd "~1.1.0" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.7.0" - finalhandler "0.5.1" - fresh "0.3.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.1" - path-to-regexp "0.1.7" - proxy-addr "~1.1.3" - qs "6.2.0" - range-parser "~1.2.0" - send "0.14.2" - serve-static "~1.11.2" - type-is "~1.6.14" - utils-merge "1.0.0" - vary "~1.1.0" - -express@^4.15.2: +express@^4.12.2, express@^4.15.2: version "4.15.2" resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" dependencies: @@ -3038,16 +2913,6 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.1.tgz#2c400d8d4530935bc232549c5fa385ec07de6fcd" - dependencies: - debug "~2.2.0" - escape-html "~1.0.3" - on-finished "~2.3.0" - statuses "~1.3.1" - unpipe "~1.0.0" - finalhandler@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.0.tgz#b5691c2c0912092f18ac23e9416bde5cd7dc6755" @@ -3167,10 +3032,6 @@ frameguard@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.0.0.tgz#7bcad469ee7b96e91d12ceb3959c78235a9272e9" -fresh@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" - fresh@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" @@ -3756,7 +3617,7 @@ htmlparser2@~3.8.1: entities "1.0" readable-stream "1.1" -http-errors@~1.5.0, http-errors@~1.5.1: +http-errors@~1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" dependencies: @@ -4269,19 +4130,7 @@ istanbul-lib-hook@^1.0.0: dependencies: append-transform "^0.4.0" -istanbul-lib-instrument@^1.3.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.4.2.tgz#0e2fdfac93c1dabf2e31578637dc78a19089f43e" - dependencies: - babel-generator "^6.18.0" - babel-template "^6.16.0" - babel-traverse "^6.18.0" - babel-types "^6.18.0" - babylon "^6.13.0" - istanbul-lib-coverage "^1.0.0" - semver "^5.3.0" - -istanbul-lib-instrument@^1.6.2: +istanbul-lib-instrument@^1.3.0, istanbul-lib-instrument@^1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.6.2.tgz#dac644f358f51efd6113536d7070959a0111f73b" dependencies: @@ -4912,6 +4761,13 @@ lru-cache@2, lru-cache@^2.5.0: version "2.7.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" +lru-cache@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + dependencies: + pseudomap "^1.0.1" + yallist "^2.0.0" + lru-cache@~2.6.5: version "2.6.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.6.5.tgz#e56d6354148ede8d7707b58d143220fd08df0fd5" @@ -6280,18 +6136,18 @@ postcss@5.1.2: source-map "^0.5.6" supports-color "^3.1.2" -postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.19, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.1.2, postcss@^5.2.11, postcss@^5.2.4, postcss@^5.2.5: - version "5.2.11" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.11.tgz#ff29bcd6d2efb98bfe08a022055ec599bbe7b761" +postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.19, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.8, postcss@^5.1.2, postcss@^5.2.15, postcss@^5.2.4, postcss@^5.2.5: + version "5.2.16" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.16.tgz#732b3100000f9ff8379a48a53839ed097376ad57" dependencies: chalk "^1.1.3" js-base64 "^2.1.9" source-map "^0.5.6" supports-color "^3.2.3" -postcss@^5.2.15: - version "5.2.16" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.16.tgz#732b3100000f9ff8379a48a53839ed097376ad57" +postcss@^5.0.6, postcss@^5.2.11: + version "5.2.11" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.11.tgz#ff29bcd6d2efb98bfe08a022055ec599bbe7b761" dependencies: chalk "^1.1.3" js-base64 "^2.1.9" @@ -6412,6 +6268,10 @@ ps-tree@^1.0.1: dependencies: event-stream "~3.3.0" +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + public-encrypt@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" @@ -6543,15 +6403,7 @@ q@^1.1.2: version "1.4.1" resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" -qs@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" - -qs@6.2.1, qs@^6.1.0, qs@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625" - -qs@6.4.0: +qs@6.4.0, qs@^6.1.0, qs@^6.2.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -6828,11 +6680,7 @@ redis-commands@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.3.1.tgz#81d826f45fa9c8b2011f4cd7a0fe597d241d442b" -redis-parser@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.4.0.tgz#018ea743077aae944d0b798b2fd12587320bf3c9" - -redis-parser@^2.5.0: +redis-parser@^2.0.0, redis-parser@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.5.0.tgz#79fc2b1d4a6e4d2870b35368433639271fca2617" @@ -6840,15 +6688,7 @@ redis@^0.12.1: version "0.12.1" resolved "https://registry.yarnpkg.com/redis/-/redis-0.12.1.tgz#64df76ad0fc8acebaebd2a0645e8a48fac49185e" -redis@^2.1.0, redis@~2.6.0-2: - version "2.6.5" - resolved "https://registry.yarnpkg.com/redis/-/redis-2.6.5.tgz#87c1eff4a489f94b70871f3d08b6988f23a95687" - dependencies: - double-ended-queue "^2.1.0-0" - redis-commands "^1.2.0" - redis-parser "^2.0.0" - -redis@^2.7.1: +redis@^2.1.0, redis@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/redis/-/redis-2.7.1.tgz#7d56f7875b98b20410b71539f1d878ed58ebf46a" dependencies: @@ -6856,6 +6696,14 @@ redis@^2.7.1: redis-commands "^1.2.0" redis-parser "^2.5.0" +redis@~2.6.0-2: + version "2.6.5" + resolved "https://registry.yarnpkg.com/redis/-/redis-2.6.5.tgz#87c1eff4a489f94b70871f3d08b6988f23a95687" + dependencies: + double-ended-queue "^2.1.0-0" + redis-commands "^1.2.0" + redis-parser "^2.0.0" + reds@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/reds/-/reds-0.2.5.tgz#38a767f7663cd749036848697d82c74fd29bc01f" @@ -7056,9 +6904,11 @@ resolve-from@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" -resolve@^1.1.6, resolve@^1.1.7: - version "1.2.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235" + dependencies: + path-parse "^1.0.5" restore-cursor@^1.0.1: version "1.0.1" @@ -7172,24 +7022,6 @@ semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" -send@0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.14.2.tgz#39b0438b3f510be5dc6f667a11f71689368cdeef" - dependencies: - debug "~2.2.0" - depd "~1.1.0" - destroy "~1.0.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.7.0" - fresh "0.3.0" - http-errors "~1.5.1" - mime "1.3.4" - ms "0.7.2" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.3.1" - send@0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" @@ -7217,15 +7049,6 @@ serve-static@1.12.1: parseurl "~1.3.1" send "0.15.1" -serve-static@~1.11.2: - version "1.11.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.2.tgz#2cf9889bd4435a320cc36895c9aa57bd662e6ac7" - dependencies: - encodeurl "~1.0.1" - escape-html "~1.0.3" - parseurl "~1.3.1" - send "0.14.2" - set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -7252,6 +7075,16 @@ sha.js@^2.3.6: dependencies: inherits "^2.0.1" +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + shelljs@0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.0.tgz#ce1ed837b4b0e55b5ec3dab84251ab9dbdc0c7ec" @@ -8128,7 +7961,7 @@ which@1.1.1: dependencies: is-absolute "^0.1.7" -which@^1.1.1: +which@^1.1.1, which@^1.2.9: version "1.2.12" resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" dependencies: @@ -8230,6 +8063,10 @@ y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" +yallist@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + yargs-parser@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4"