diff --git a/packages/cp-gql-schema/schema.gql b/packages/cp-gql-schema/schema.gql
index d416929c..2effa162 100644
--- a/packages/cp-gql-schema/schema.gql
+++ b/packages/cp-gql-schema/schema.gql
@@ -152,12 +152,22 @@ enum InstanceStatus {
UNKNOWN
}
+enum HealthyStatus {
+ HEALTHY
+ UNHEALTHY
+ MAINTENANCE
+ UNKNOWN
+ UNAVAILABLE
+}
+
type Instance {
id: ID!
name: String!
machineId: ID!
status: InstanceStatus!
- healthy: Boolean
+ healthy: HealthyStatus
+ watchers: [String]
+ jobs: [String]
}
type Datacenter {
diff --git a/packages/normalized-styled-components/test/__snapshots__/index.js.snap b/packages/normalized-styled-components/test/__snapshots__/index.js.snap
index 43754094..9ed3f0f6 100644
--- a/packages/normalized-styled-components/test/__snapshots__/index.js.snap
+++ b/packages/normalized-styled-components/test/__snapshots__/index.js.snap
@@ -3,7 +3,6 @@
exports[`renders correctly 1`] = `
.jleQxG {
background-color: transparent;
- -webkit-text-decoration-skip: objects;
text-decoration-skip: objects;
}
@@ -72,7 +71,6 @@ exports[`renders correctly 1`] = `
line-height: 1.15;
margin: 0;
overflow: visible;
- -webkit-text-transform: none;
text-transform: none;
-webkit-appearance: button;
-moz-appearance: button;
@@ -374,7 +372,6 @@ exports[`renders correctly 1`] = `
font-size: 100%;
line-height: 1.15;
margin: 0;
- -webkit-text-transform: none;
text-transform: none;
}
diff --git a/packages/portal-api/lib/data/index.js b/packages/portal-api/lib/data/index.js
index fd18b7c3..ec26f654 100644
--- a/packages/portal-api/lib/data/index.js
+++ b/packages/portal-api/lib/data/index.js
@@ -23,7 +23,7 @@ const VAsync = require('vasync');
// local modules
const Transform = require('./transform');
-const { DEPLOYMENT_GROUP, SERVICE, HASH } = require('../watch');
+const { DEPLOYMENT_GROUP, SERVICE, HASH } = require('../watch/machines');
const NON_IMPORTABLE_STATES = [
@@ -77,7 +77,7 @@ class Data extends EventEmitter {
this._db = new Penseur.Db(settings.name, settings.db);
this._dockerCompose = new DockerClient(settings.dockerComposeHost);
this._docker = new Dockerode(settings.docker);
- this._watcher = null;
+ this._machines = null;
this._triton = null;
Triton.createClient({
@@ -96,8 +96,8 @@ class Data extends EventEmitter {
});
}
- setWatcher (watcher) {
- this._watcher = watcher;
+ setMachinesWatcher (machinesWatcher) {
+ this._machines = machinesWatcher;
}
connect (cb) {
@@ -1854,10 +1854,6 @@ class Data extends EventEmitter {
updateInstance (clientInstance, cb) {
const instance = Transform.toInstance(clientInstance);
- if (typeof instance.healthy !== 'boolean') {
- instance.healthy = null;
- }
-
this._db.instances.update([instance], (err) => {
if (err) {
return cb(err);
@@ -2073,11 +2069,11 @@ class Data extends EventEmitter {
}
getImportableDeploymentGroups (args, cb) {
- if (!this._watcher) {
+ if (!this._machines) {
return cb(null, []);
}
- const machines = this._watcher.getContainers();
+ const machines = this._machines.getContainers();
if (!Array.isArray(machines)) {
return cb(null, []);
@@ -2123,12 +2119,12 @@ class Data extends EventEmitter {
importDeploymentGroup ({ deploymentGroupSlug }, cb) {
console.log(`-> import requested for ${deploymentGroupSlug}`);
- if (!this._watcher) {
+ if (!this._machines) {
console.log('-> watcher not yet defined');
return cb(null, null);
}
- const machines = this._watcher.getContainers();
+ const machines = this._machines.getContainers();
if (!Array.isArray(machines)) {
console.log('-> no machines found');
diff --git a/packages/portal-api/lib/data/transform.js b/packages/portal-api/lib/data/transform.js
index 73b03731..5b0497ff 100644
--- a/packages/portal-api/lib/data/transform.js
+++ b/packages/portal-api/lib/data/transform.js
@@ -165,19 +165,22 @@ exports.fromInstance = function (instance) {
name: instance.name,
machineId: instance.machine_id,
status: instance.status,
- ips: instance.ips,
- healthy: instance.healthy
+ healthy: instance.healthy,
+ watchers: instance.watchers,
+ jobs: instance.jobs
};
};
+
exports.toInstance = function (clientInstance) {
return clean({
id: clientInstance.id,
name: clientInstance.name,
machine_id: clientInstance.machineId,
status: clientInstance.status,
- ips: clientInstance.ips,
- healthy: clientInstance.healthy
+ healthy: clientInstance.healthy,
+ watchers: clientInstance.watchers,
+ jobs: clientInstance.jobs
});
};
diff --git a/packages/portal-api/lib/index.js b/packages/portal-api/lib/index.js
index af6b0e65..41519c49 100644
--- a/packages/portal-api/lib/index.js
+++ b/packages/portal-api/lib/index.js
@@ -6,8 +6,8 @@ const Piloted = require('piloted');
const Data = require('./data');
const Pack = require('../package.json');
const Resolvers = require('./resolvers');
-const Watch = require('./watch');
-const WatchHealth = require('./watch/health');
+const ContainerPilotWatcher = require('./watch/container-pilot');
+const MachinesWatcher = require('./watch/machines');
const internals = {};
@@ -24,7 +24,8 @@ module.exports = function (server, options, next) {
}
const data = new Data(options.data);
- const watcher = new Watch(Object.assign(options.watch, {
+ const cpWatcher = new ContainerPilotWatcher(Object.assign(options.watch, { data }));
+ const machinesWatcher = new MachinesWatcher(Object.assign(options.watch, {
data
}));
@@ -32,10 +33,9 @@ module.exports = function (server, options, next) {
// portal depends on watcher and vice-versa
// I'm sure there is a better way to organize this domains
// but this works for now
- data.setWatcher(watcher);
+ data.setMachinesWatcher(machinesWatcher);
- const healthWatcher = new WatchHealth(Object.assign(options.health, { data }));
- healthWatcher.on('error', (err) => {
+ cpWatcher.on('error', (err) => {
server.log(['error'], err);
});
@@ -51,8 +51,9 @@ module.exports = function (server, options, next) {
server.bind(data);
Piloted.on('refresh', internals.refresh(data));
- watcher.poll();
- healthWatcher.poll();
+
+ machinesWatcher.poll();
+ cpWatcher.poll();
server.register([
{
diff --git a/packages/portal-api/lib/watch/container-pilot.js b/packages/portal-api/lib/watch/container-pilot.js
new file mode 100644
index 00000000..d909c35e
--- /dev/null
+++ b/packages/portal-api/lib/watch/container-pilot.js
@@ -0,0 +1,429 @@
+'use strict';
+
+const Events = require('events');
+const Flatten = require('lodash.flatten');
+const Triton = require('triton');
+const VAsync = require('vasync');
+const Wreck = require('wreck');
+const CIDRMatcher = require('cidr-matcher');
+const ForceArray = require('force-array');
+const Get = require('lodash.get');
+const Uniq = require('lodash.uniq');
+const Queue = require('./queue');
+
+module.exports = class ContainerPilotWatcher extends Events {
+ constructor (options) {
+ super();
+
+ options = options || {};
+
+ // todo assert options
+ this._data = options.data;
+ this._frequency = options.frequency || 1000;
+
+ Triton.createClient({
+ profile: {
+ url: options.url || process.env.SDC_URL,
+ account: options.account || process.env.SDC_ACCOUNT,
+ keyId: options.keyId || process.env.SDC_KEY_ID
+ }
+ }, (err, client) => {
+ if (err) {
+ this.emit('error', err);
+ return;
+ }
+
+ this._triton = client.cloudapi;
+ });
+ }
+
+ poll () {
+ if (this._timeoutId) {
+ return;
+ }
+
+ this._timeoutId = setTimeout(() => {
+ this.check((err) => {
+ if (err) {
+ this.emit('error', err);
+ }
+
+ delete this._timeoutId;
+ this.poll();
+ });
+ }, this._frequency);
+ }
+
+ _getDeploymentGroups (cb) {
+ const getInstances = (service, next) => {
+ service.instances({}, (err, instances) => {
+ if (err) {
+ return next(err);
+ }
+
+ next(null, Object.assign({}, service, {
+ instances
+ }));
+ });
+ };
+
+ const getServices = (deploymentGroup, next) => {
+ deploymentGroup.services({}, (err, services) => {
+ if (err) {
+ return next(err);
+ }
+
+ VAsync.forEachParallel({
+ inputs: services,
+ func: getInstances
+ }, (err, result) => {
+ if (err) {
+ return next(err);
+ }
+
+ next(null, Object.assign({}, deploymentGroup, {
+ services: result.successes
+ }));
+ });
+ });
+ };
+
+ const handleDeploymentGroups = (err, deploymentGroups) => {
+ if (err) {
+ return cb(err);
+ }
+
+ VAsync.forEachParallel({
+ inputs: deploymentGroups,
+ func: getServices
+ }, (err, result) => {
+ cb(err, result.successes);
+ });
+ };
+
+ const getDeploymentGroups = (err, portal) => {
+ if (err) {
+ return cb(err);
+ }
+
+ portal.deploymentGroups({}, handleDeploymentGroups);
+ };
+
+ this._data.getPortal({}, getDeploymentGroups);
+ }
+
+ _getNetworks (networkIds = [], cb) {
+ VAsync.forEachParallel({
+ inputs: networkIds,
+ func: (id, next) => {
+ this._triton.getNetwork(id, next);
+ }
+ }, (err, results) => {
+ cb(err, ForceArray((results || {}).successes));
+ });
+ }
+
+ _getPublicIps (machine, cb) {
+ this._getNetworks(machine.networks, (err, networks) => {
+ if (err) {
+ return cb(err);
+ }
+
+ const privateNetworkSubnets = networks
+ .filter((network) => {
+ return !network['public'];
+ })
+ .map((network) => {
+ return network.subnet;
+ })
+ .filter(Boolean);
+
+ const cidr = new CIDRMatcher(privateNetworkSubnets);
+
+ const nonPrivateIps = machine.ips.filter((ip) => {
+ return !cidr.contains(ip);
+ });
+
+ cb(null, nonPrivateIps);
+ });
+ }
+
+ _fetchInstanceStatus (instance, cb) {
+ const { machineId } = instance;
+
+ const handleStatuses = (err, results) => {
+ if (err) {
+ this.emit('error', err);
+ return cb();
+ }
+
+ const statuses = ForceArray((results || {}).successes);
+
+ const status = statuses.filter(Boolean).shift();
+
+ if (!status) {
+ return cb(null, instance);
+ }
+
+ const services = ForceArray(status.Services).filter(({ Name }) => {
+ return Name !== 'containerpilot';
+ });
+
+ cb(null, Object.assign({}, instance, {
+ cp: Object.assign({}, status, {
+ Services: services
+ })
+ }));
+ };
+
+ const fetchStatus = (ip, next) => {
+ Wreck.get(`http://${ip}:9090/status`, {
+ timeout: 1000 // 1s
+ }, (err, res, payload) => {
+ if (err) {
+ this.emit('error', err);
+ return next();
+ }
+
+ if (Buffer.isBuffer(payload)) {
+ payload = payload.toString();
+ }
+
+ try {
+ const status = JSON.parse(payload);
+ next(null, status);
+ } catch (err) {
+ next();
+ }
+ });
+ };
+
+ const handlePublicIps = (err, ips) => {
+ if (err) {
+ this.emit('error', err);
+ return cb();
+ }
+
+ VAsync.forEachParallel({
+ inputs: ips,
+ func: fetchStatus
+ }, handleStatuses);
+ };
+
+ this._triton.getMachine(machineId, (err, machine) => {
+ if (err) {
+ this.emit('error', err);
+ return cb();
+ }
+
+ this._getPublicIps(machine, handlePublicIps);
+ });
+ }
+
+ _fetchServiceStatus (service, cb) {
+ VAsync.forEachParallel({
+ inputs: service.instances,
+ func: (instance, next) => {
+ this._fetchInstanceStatus(instance, next);
+ }
+ }, (err, results) => {
+ if (err) {
+ this.emit('error', err);
+ }
+
+ cb(null, Object.assign({}, service, {
+ instances: ForceArray((results || {}).successes)
+ }));
+ });
+ }
+
+ _fetchDeploymentGroupStatus (dg, cb) {
+ VAsync.forEachParallel({
+ inputs: dg.services,
+ func: (service, next) => {
+ this._fetchServiceStatus(service, next);
+ }
+ }, (err, results) => {
+ if (err) {
+ this.emit('error', err);
+ }
+
+ cb(null, Object.assign({}, dg, {
+ services: ForceArray((results || {}).successes)
+ }));
+ });
+ }
+
+ _saveInstance ({ id, healthy, watchers, jobs }, cb) {
+ if (!id) {
+ return cb();
+ }
+
+ this._data.updateInstance({
+ id,
+ healthy,
+ watchers,
+ jobs
+ }, cb);
+ }
+
+ _saveService ({ id, instances, connections }, cb) {
+ if (!id) {
+ return cb();
+ }
+
+ VAsync.forEachParallel({
+ inputs: instances,
+ func: (instance, next) => {
+ this._saveInstance(instance, next);
+ }
+ }, (err) => {
+ if (err) {
+ return cb(err);
+ }
+
+ this._data.updateService({
+ id,
+ connections
+ }, cb);
+ });
+ }
+
+ _saveDeploymentGroup (dg, cb) {
+ VAsync.forEachParallel({
+ inputs: dg.services,
+ func: (service, next) => {
+ this._saveService(service, next);
+ }
+ }, cb);
+ }
+
+ check (cb) {
+ if (!this._triton) {
+ return cb();
+ }
+
+ const resolveServiceConnections = ({ services, service }) => {
+ const watches = Uniq(
+ Flatten(ForceArray(service.instances).map(({ watches }) => { return watches; }))
+ );
+
+ return watches
+ .map((jobName) => {
+ return services.reduce((serviceId, service) => {
+ if (serviceId) {
+ return serviceId;
+ }
+
+ const thisServiceJobs = Uniq(
+ Flatten(ForceArray(service.instances).map(({ jobs }) => { return jobs; }))
+ );
+
+ if (thisServiceJobs.indexOf(jobName) >= 0) {
+ return service.id;
+ }
+
+ return serviceId;
+ }, null);
+ })
+ .filter(Boolean);
+ };
+
+ const resolveInstanceHealth = ({ name }, instance) => {
+ if (!instance) {
+ return;
+ }
+
+ if (!instance.cp) {
+ return 'UNAVAILABLE';
+ }
+
+ const jobNames = Get(instance, 'cp.Services');
+
+ const serviceJobs = jobNames.filter(({ Name }) => { return Name === name; });
+
+ if (serviceJobs.length) {
+ return serviceJobs.shift().Status.toUpperCase();
+ }
+
+ const almostJobNameRegexp = new RegExp(`${name}-.*`);
+ const almostServiceJobs = jobNames.filter((n) => {
+ return almostJobNameRegexp.test(n);
+ });
+
+ if (almostServiceJobs.length) {
+ return almostServiceJobs.shift().Status.toUpperCase();
+ }
+
+ return 'UNKNOWN';
+ };
+
+ const handleStatuses = (err, results) => {
+ if (err) {
+ this.emit('error', err);
+ }
+
+ const dgs = ForceArray((results || {}).successes)
+ .map((dg) => {
+ return Object.assign({}, dg, {
+ services: ForceArray(dg.services).map((service) => {
+ return Object.assign({}, service, {
+ instances: ForceArray(service.instances).map((instance) => {
+ return Object.assign({}, instance, {
+ healthy: resolveInstanceHealth(service, instance),
+ jobs: Get(instance, 'cp.Services', []).map(
+ ({ Name }) => { return Name; }
+ ),
+ watches: Get(instance, 'cp.Watches', [])
+ });
+ })
+ });
+ })
+ });
+ })
+ .map((dg) => {
+ return Object.assign({}, dg, {
+ services: ForceArray(dg.services).map((service) => {
+ return Object.assign({}, service, {
+ connections: resolveServiceConnections({
+ services: dg.services,
+ service
+ })
+ });
+ })
+ });
+ });
+
+ VAsync.forEachParallel({
+ inputs: dgs,
+ func: (dg, next) => {
+ Queue(dg.id, () => {
+ return new Promise((resolve) => {
+ this._saveDeploymentGroup(dg, (err) => {
+ resolve();
+ next(err);
+ });
+ });
+ });
+ }
+ }, cb);
+ };
+
+ const fetchStatuses = (err, dgs) => {
+ if (err) {
+ this.emit('error', err);
+ return cb();
+ }
+
+ VAsync.forEachParallel({
+ inputs: dgs,
+ func: (dg, next) => {
+ this._fetchDeploymentGroupStatus(dg, next);
+ }
+ }, handleStatuses);
+ };
+
+ this._getDeploymentGroups(fetchStatuses);
+ }
+};
+
diff --git a/packages/portal-api/lib/watch/health.js b/packages/portal-api/lib/watch/health.js
deleted file mode 100644
index f125e4a0..00000000
--- a/packages/portal-api/lib/watch/health.js
+++ /dev/null
@@ -1,159 +0,0 @@
-'use strict';
-
-const Events = require('events');
-const Consulite = require('consulite');
-const VAsync = require('vasync');
-
-
-module.exports = class Health extends Events {
- constructor (options) {
- super();
-
- options = options || {};
-
- // todo assert options
- this._data = options.data;
- this._frequency = options.frequency || 2000;
- }
-
- poll () {
- if (this._timeoutId) {
- return;
- }
-
- this._timeoutId = setTimeout(() => {
- this.check((err) => {
- if (err) {
- this.emit('error', err);
- }
-
- delete this._timeoutId;
- this.poll();
- });
- }, this._frequency);
- }
-
- // check() follows these steps:
- // 1. grab all services from the db
- // 2. filter to only the unique consul hosts
- // 3. grab all instances from the db
- // 4. query each consul host for service names
- // 5. query the respective consul host for service health
- // 6. match node to instance using the address and update `healthy` if the status changes
- check (cb) {
- // 1. grab all services from the db
- this._data.services.all((err, services) => {
- if (err) {
- return cb(err);
- }
-
- if (!services) {
- return cb();
- }
-
- // 2. filter to only the unique consul hosts
- const consulHosts = [];
- services.forEach((service) => {
- if (!service.consul) {
- return;
- }
-
- if (consulHosts.indexOf(service.consul) === -1) {
- consulHosts.push(service.consul);
- }
- });
-
- // 3. grab all instances from the db
- this._data.instances.all((err, instances) => {
- if (err) {
- return cb(err);
- }
-
- // we match consul nodes using the IP address, remove those that won't match
- instances = instances.filter((instance) => {
- return instance.ips && instance.ips.length;
- });
-
- // include consul host on each instance
- // helps to identify the correct instance when comparing addresses
- instances.forEach((instance) => {
- const service = services.find((service) => {
- return (service.instance_ids.indexOf(instance.id) !== -1);
- });
-
- if (service) {
- instance.consul = service.consul;
- }
- });
-
- VAsync.forEachParallel({
- inputs: consulHosts,
- // 4. query each consul host for service names
- // 5. query the respective consul host for service health
- func: this._checkServicesHealth
- }, (err, results) => {
- if (err) {
- return cb(err);
- }
-
- // 6. match node to instance using the address and update `healthy` if the status changes
- this._findAndUpdateInstances(instances, results.successes, cb);
- });
- });
- });
- }
-
- _checkServicesHealth (consul, cb) {
- const consulite = new Consulite({ consul });
-
- consulite.getServiceNames((err, consulServices) => {
- if (err) {
- return cb(err);
- }
-
- // filter out telemetry services
- consulServices = consulServices.filter((consulService) => {
- return consulService !== 'containerpilot';
- });
-
- VAsync.forEachParallel({
- inputs: consulServices,
- func: (consulService, next) => {
- consulite.getServiceStatus(consulService, (err, nodes) => {
- if (err) {
- return next(err);
- }
-
- nodes = nodes.map((node) => {
- node.consul = consul;
- return node;
- });
-
- next(null, nodes);
- });
- }
- }, cb);
- });
- }
-
- _findAndUpdateInstances (instances, nodes, cb) {
- VAsync.forEachPipeline({
- inputs: nodes,
- func: (node, next) => {
- const healthy = (node.status === 'passing');
-
- const instance = instances.find((instance) => {
- return (instance.ips.indexOf(node.address) !== -1) &&
- (instance.consul === node.consul) &&
- (instance.healthy !== healthy);
- });
-
- if (!instance) {
- return next();
- }
-
- this._data.updateInstance({ id: instance.id, healthy }, next);
- }
- }, cb);
- }
-};
diff --git a/packages/portal-api/lib/watch/index.js b/packages/portal-api/lib/watch/machines.js
similarity index 97%
rename from packages/portal-api/lib/watch/index.js
rename to packages/portal-api/lib/watch/machines.js
index c9540f8d..e10b8587 100644
--- a/packages/portal-api/lib/watch/index.js
+++ b/packages/portal-api/lib/watch/machines.js
@@ -1,13 +1,13 @@
'use strict';
// const Assert = require('assert');
-const Throat = require('throat');
const TritonWatch = require('triton-watch');
const Get = require('lodash.get');
const Find = require('lodash.find');
const Util = require('util');
const ForceArray = require('force-array');
const VAsync = require('vasync');
+const Queue = require('./queue');
const DEPLOYMENT_GROUP = 'docker:label:com.docker.compose.project';
@@ -52,7 +52,7 @@ const SERVICE_DELETING_STATUSES = [
'UNKNOWN'
];
-module.exports = class Watcher {
+module.exports = class MachineWatcher {
constructor (options) {
options = options || {};
@@ -71,7 +71,6 @@ module.exports = class Watcher {
}
});
- this._queues = {};
this._waitingForPlan = [];
this._isTritonWatchPolling = false;
@@ -112,16 +111,6 @@ module.exports = class Watcher {
return this._tritonWatch.getContainers();
}
- pushToQueue (deploymentGroupId, cb) {
- if (this._queues[deploymentGroupId]) {
- this._queues[deploymentGroupId](cb);
- return;
- }
-
- this._queues[deploymentGroupId] = Throat(1);
- this._queues[deploymentGroupId](cb);
- }
-
getDeploymentGroup (name, cb) {
this._data.getDeploymentGroup({ name }, (err, deploymentGroup) => {
if (err) {
@@ -178,7 +167,6 @@ module.exports = class Watcher {
const instance = {
name: machine.name,
status,
- ips: machine.ips,
machineId: machine.id
};
@@ -203,7 +191,6 @@ module.exports = class Watcher {
const updatedInstance = {
id: instance.id,
- ips: machine.ips,
status: (machine.state || '').toUpperCase()
};
@@ -630,7 +617,7 @@ module.exports = class Watcher {
return;
}
- this.pushToQueue(deploymentGroup.id, () => {
+ Queue(deploymentGroup.id, () => {
return new Promise((resolve) => {
assertService(deploymentGroup, (err) => {
if (err) {
diff --git a/packages/portal-api/lib/watch/queue.js b/packages/portal-api/lib/watch/queue.js
new file mode 100644
index 00000000..07d822eb
--- /dev/null
+++ b/packages/portal-api/lib/watch/queue.js
@@ -0,0 +1,18 @@
+'use strict';
+
+const Throat = require('throat');
+
+module.exports = (() => {
+ const _queues = {};
+
+ // pushToQueue
+ return (id, cb) => {
+ if (_queues[id]) {
+ _queues[id](cb);
+ return;
+ }
+
+ _queues[id] = Throat(1);
+ _queues[id](cb);
+ };
+})();
diff --git a/packages/portal-api/package.json b/packages/portal-api/package.json
index ed13a82a..fec96853 100644
--- a/packages/portal-api/package.json
+++ b/packages/portal-api/package.json
@@ -27,11 +27,12 @@
"hapi-swagger": "^7.7.0",
"inert": "^4.2.0",
"lab": "^14.0.1",
- "vision": "^4.1.1"
+ "vision": "^4.1.1",
+ "wreck": "^12.2.2"
},
"dependencies": {
"boom": "^5.1.0",
- "consulite": "^2.0.0",
+ "cidr-matcher": "^1.0.5",
"docker-compose-client": "^1.0.8",
"dockerode": "^2.5.0",
"graphi": "^2.2.1",
@@ -40,6 +41,7 @@
"lodash.find": "^4.6.0",
"lodash.flatten": "^4.4.0",
"lodash.get": "^4.4.2",
+ "lodash.uniq": "^4.5.0",
"lodash.uniqby": "^4.7.0",
"param-case": "^2.1.1",
"penseur": "^7.12.3",
diff --git a/yarn.lock b/yarn.lock
index 76fc3048..ef550fe1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -198,7 +198,7 @@ ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
-ansi-styles@^3.0.0:
+ansi-styles@^3.0.0, ansi-styles@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.1.0.tgz#09c202d5c917ec23188caa5c9cb9179cd9547750"
dependencies:
@@ -220,8 +220,8 @@ anymatch@^1.3.0:
micromatch "^2.1.5"
apollo-client@^1.4.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-1.7.0.tgz#3d6fdf6ead0a07d3e02d32d9191f26cbcfb6e4f6"
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-1.8.0.tgz#3b5d1976a06a0f82b2fc66fe71754868193dadb9"
dependencies:
graphql "^0.10.0"
graphql-anywhere "^3.0.1"
@@ -456,8 +456,8 @@ arrify@^1.0.0, arrify@^1.0.1:
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
asap@^2.0.0, asap@~2.0.3:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
asn1.js@^4.0.0:
version "4.9.1"
@@ -497,10 +497,6 @@ ast-types@0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.0.tgz#c8721c8747ae4d5b29b929e99c5317b4e8745623"
-ast-types@0.9.6:
- version "0.9.6"
- resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9"
-
async-each@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
@@ -543,14 +539,14 @@ autoprefixer@^6.0.0:
postcss-value-parser "^3.2.3"
ava-init@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/ava-init/-/ava-init-0.2.0.tgz#9304c8b4c357d66e3dfdae1fbff47b1199d5c55d"
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/ava-init/-/ava-init-0.2.1.tgz#75ac4c8553326290d2866e63b62fa7035684bd58"
dependencies:
arr-exclude "^1.0.0"
- execa "^0.5.0"
+ execa "^0.7.0"
has-yarn "^1.0.0"
read-pkg-up "^2.0.0"
- write-pkg "^2.0.0"
+ write-pkg "^3.1.0"
ava@0.19.1:
version "0.19.1"
@@ -1385,8 +1381,8 @@ backoff@2.4.1, backoff@^2.4.1:
precond "0.2"
bail@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.1.tgz#912579de8b391aadf3c5fdf4cd2a0fc225df3bc2"
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.2.tgz#f7d6c1731630a9f9f0d4d35ed1f962e2074a1764"
balanced-match@^0.4.0:
version "0.4.2"
@@ -1766,12 +1762,12 @@ camelcase@^4.0.0, camelcase@^4.1.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
- version "1.0.30000698"
- resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000698.tgz#623a2de3458ceca379846a8f170e7b1771c7c3a3"
+ version "1.0.30000699"
+ resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000699.tgz#5af491ab1c777561a32b43fe253d6a7071ccf979"
caniuse-lite@^1.0.30000684:
- version "1.0.30000698"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000698.tgz#8102e8978b1f36962f2a102432e4bf4eac7b6cbe"
+ version "1.0.30000699"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000699.tgz#2a187b737edaa9ebedbbb56edcb53e994eceda0c"
capture-stack-trace@^1.0.0:
version "1.0.0"
@@ -1824,6 +1820,14 @@ chalk@^0.4.0:
has-color "~0.1.0"
strip-ansi "~0.1.0"
+chalk@^2.0.0, chalk@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.0.1.tgz#dbec49436d2ae15f536114e76d14656cdbc0f44d"
+ dependencies:
+ ansi-styles "^3.1.0"
+ escape-string-regexp "^1.0.5"
+ supports-color "^4.0.0"
+
chalk@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174"
@@ -1835,16 +1839,16 @@ chalk@~0.5.1:
supports-color "^0.2.0"
character-entities-html4@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.0.tgz#1ab08551d3ce1fa1df08d00fb9ca1defb147a06c"
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.1.tgz#359a2a4a0f7e29d3dc2ac99bdbe21ee39438ea50"
character-entities-legacy@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.0.tgz#b18aad98f6b7bcc646c1e4c81f9f1956376a561a"
character-entities@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.0.tgz#a683e2cf75dbe8b171963531364e58e18a1b155f"
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.1.tgz#f76871be5ef66ddb7f8f8e3478ecc374c27d6dca"
character-reference-invalid@^1.0.0:
version "1.1.0"
@@ -1875,6 +1879,12 @@ ci-info@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534"
+cidr-matcher@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/cidr-matcher/-/cidr-matcher-1.0.5.tgz#1805e49751be8fc8279a73355574e31c9f49666b"
+ dependencies:
+ ip "^1.0.2"
+
cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
@@ -2172,13 +2182,6 @@ consulite@1.6.x:
or-promise "1.x.x"
wreck "10.x.x"
-consulite@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/consulite/-/consulite-2.0.0.tgz#4d35228d24f70a8fb01fdb8ed921d4e54d8bbb16"
- dependencies:
- or-promise "1.x.x"
- wreck "12.x.x"
-
contains-path@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
@@ -2518,8 +2521,8 @@ cryptiles@3.x.x:
boom "5.x.x"
crypto-browserify@^3.11.0:
- version "3.11.0"
- resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522"
+ version "3.11.1"
+ resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f"
dependencies:
browserify-cipher "^1.0.0"
browserify-sign "^4.0.0"
@@ -2819,8 +2822,8 @@ dale-chall-formula@^1.0.0:
resolved "https://registry.yarnpkg.com/dale-chall-formula/-/dale-chall-formula-1.0.1.tgz#de3a82d485c7ab7b64c2c9c046f7f3cb75e177fd"
dale-chall@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/dale-chall/-/dale-chall-1.0.0.tgz#7f6e7ca357bdb3552c1ddb3c750bd9300cb895b7"
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/dale-chall/-/dale-chall-1.0.1.tgz#e2dc01ba31784261520dc94f3e24367b437a677d"
damerau-levenshtein@^1.0.0:
version "1.0.4"
@@ -3231,8 +3234,8 @@ es-to-primitive@^1.1.1:
is-symbol "^1.0.1"
es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14:
- version "0.10.23"
- resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.23.tgz#7578b51be974207a5487821b56538c224e4e7b38"
+ version "0.10.24"
+ resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.24.tgz#a55877c9924bc0c8d9bd3c2cbe17495ac1709b14"
dependencies:
es6-iterator "2"
es6-symbol "~3.1"
@@ -3346,8 +3349,8 @@ eslint-module-utils@^2.1.1:
pkg-dir "^1.0.0"
eslint-plugin-flowtype@^2.34.0:
- version "2.34.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.34.1.tgz#ea109175645b05d37baeac53b9b65066d79b9446"
+ version "2.35.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.35.0.tgz#d17494f0ae8b727c632d8b9d4b4a848e7e0c04af"
dependencies:
lodash "^4.15.0"
@@ -3507,9 +3510,9 @@ esprima@^2.6.0, esprima@~2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
-esprima@^3.1.1, esprima@~3.1.0:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+esprima@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
espurify@^1.6.0:
version "1.7.0"
@@ -3717,11 +3720,11 @@ extsprintf@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
-extsprintf@1.2.0, extsprintf@^1.2.0:
+extsprintf@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.2.0.tgz#5ad946c22f5b32ba7f8cd7426711c6e8a3fc2529"
-extsprintf@1.3.0:
+extsprintf@1.3.0, extsprintf@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
@@ -3793,8 +3796,8 @@ fill-range@^2.1.0:
repeat-string "^1.5.2"
fillers@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/fillers/-/fillers-1.1.0.tgz#0fa81fb2af369a793f2fafc08b67e60a299fc9f9"
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/fillers/-/fillers-1.1.1.tgz#9d1a8f0150d47f78a898de4cd43cf079d417148e"
finalhandler@~1.0.3:
version "1.0.3"
@@ -4358,15 +4361,15 @@ has-own-prop@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-1.0.0.tgz#7b5e04505ee55896ba32e5018098b481a2f8a0e5"
-has-symbol-support-x@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.3.0.tgz#588bd6927eaa0e296afae24160659167fc2be4f8"
+has-symbol-support-x@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.0.tgz#442d89b1d0ac6cf5ff2f7b916ee539869b93a256"
has-to-string-tag-x@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.3.0.tgz#78e3d98c3c0ec9413e970eb8d766249a1e13058f"
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.0.tgz#49d7bcde85c2409be38ac327e3e119a451657c7b"
dependencies:
- has-symbol-support-x "^1.3.0"
+ has-symbol-support-x "^1.4.0"
has-unicode@^2.0.0:
version "2.0.1"
@@ -4629,11 +4632,11 @@ inquirer@^0.12.0:
through "^2.3.6"
inquirer@^3.0.2, inquirer@^3.0.6, inquirer@^3.1.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.1.1.tgz#87621c4fba4072f48a8dd71c9f9df6f100b2d534"
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.2.0.tgz#45b44c2160c729d7578c54060b3eed94487bb42b"
dependencies:
ansi-escapes "^2.0.0"
- chalk "^1.0.0"
+ chalk "^2.0.0"
cli-cursor "^2.1.0"
cli-width "^2.0.0"
external-editor "^2.0.4"
@@ -4643,8 +4646,8 @@ inquirer@^3.0.2, inquirer@^3.0.6, inquirer@^3.1.0:
run-async "^2.2.0"
rx-lite "^4.0.8"
rx-lite-aggregates "^4.0.8"
- string-width "^2.0.0"
- strip-ansi "^3.0.0"
+ string-width "^2.1.0"
+ strip-ansi "^4.0.0"
through "^2.3.6"
insync@2.x.x:
@@ -4665,6 +4668,10 @@ invert-kv@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+ip@^1.0.2:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
+
ipaddr.js@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec"
@@ -5206,8 +5213,8 @@ jest-snapshot@^20.0.3:
pretty-format "^20.0.3"
jest-styled-components@^3.0.2:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-3.3.1.tgz#8803b9577105d11ea8681397a06f154824c8f782"
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-3.3.2.tgz#cf22c7489d417cbb19d878cdc606cec83538f4f7"
dependencies:
css "^2.2.1"
@@ -5315,11 +5322,11 @@ js-tokens@^3.0.0:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
js-yaml@^3.2.7, js-yaml@^3.4.3, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.6.0, js-yaml@^3.8.2, js-yaml@^3.8.4:
- version "3.8.4"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6"
+ version "3.9.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.0.tgz#4ffbbf25c2ac963b8299dc74da7e3740de1c18ce"
dependencies:
argparse "^1.0.7"
- esprima "^3.1.1"
+ esprima "^4.0.0"
js-yaml@~3.7.0:
version "3.7.0"
@@ -6067,8 +6074,8 @@ miller-rabin@^4.0.0:
brorand "^1.0.1"
mime-db@1.x.x:
- version "1.28.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.28.0.tgz#fedd349be06d2865b7fc57d837c6de4f17d7ac3c"
+ version "1.29.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.29.0.tgz#48d26d235589651704ac5916ca06001914266878"
mime-db@~1.27.0:
version "1.27.0"
@@ -7056,8 +7063,8 @@ pretty-ms@^2.0.0:
plur "^1.0.0"
primer-support@*:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/primer-support/-/primer-support-4.0.6.tgz#80f3bf1ceb63fda1cf2fdbcea09b632c812e1d54"
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/primer-support/-/primer-support-4.0.7.tgz#c9c433c5a597a78226870ea3d18c4bf0e96eeab4"
primer-utilities@^3.0.0:
version "3.5.0"
@@ -7552,7 +7559,7 @@ readline2@^1.0.1:
is-fullwidth-code-point "^1.0.0"
mute-stream "0.0.5"
-recast@0.11.12:
+recast@0.11.12, recast@^0.11.5:
version "0.11.12"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.12.tgz#a79e4d3f82d5d72a82ee177aeaa791e793bbe5d6"
dependencies:
@@ -7561,15 +7568,6 @@ recast@0.11.12:
private "~0.1.5"
source-map "~0.5.0"
-recast@^0.11.5:
- version "0.11.23"
- resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3"
- dependencies:
- ast-types "0.9.6"
- esprima "~3.1.0"
- private "~0.1.5"
- source-map "~0.5.0"
-
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
@@ -8295,7 +8293,7 @@ sntp@1.x.x:
dependencies:
hoek "2.x.x"
-sort-keys@^1.1.1, sort-keys@^1.1.2:
+sort-keys@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
dependencies:
@@ -8541,7 +8539,7 @@ string-width@^1.0.0, string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
-string-width@^2.0.0:
+string-width@^2.0.0, string-width@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.0.tgz#030664561fc146c9423ec7d978fe2457437fe6d0"
dependencies:
@@ -8718,12 +8716,12 @@ stylelint-selector-no-utility@^1.5.0:
stylelint "^7.0.0"
stylelint@^7.0.0, stylelint@^7.0.3, stylelint@^7.11.1:
- version "7.12.0"
- resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-7.12.0.tgz#bf302c265d7c2d6fe79b154a9fd873a80f8b4aa4"
+ version "7.13.0"
+ resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-7.13.0.tgz#111f97b6da72e775c80800d6bb6f5f869997785d"
dependencies:
autoprefixer "^6.0.0"
balanced-match "^0.4.0"
- chalk "^1.1.1"
+ chalk "^2.0.1"
colorguard "^1.2.0"
cosmiconfig "^2.1.1"
debug "^2.6.0"
@@ -8795,9 +8793,9 @@ supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3:
dependencies:
has-flag "^1.0.0"
-supports-color@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.1.0.tgz#92cc14bb3dad8928ca5656c33e19a19f20af5c7a"
+supports-color@^4.0.0, supports-color@^4.1.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.0.tgz#ad986dc7eb2315d009b4d77c8169c2231a684037"
dependencies:
has-flag "^2.0.0"
@@ -9217,8 +9215,8 @@ triton@5.2.x, triton@^5.2.0:
wordwrap "1.0.0"
trough@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.0.tgz#6bdedfe7f2aa49a6f3c432257687555957f342fd"
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.1.tgz#a9fd8b0394b0ae8fff82e0633a0a36ccad5b5f86"
try-catch@^1.0.0, try-catch@~1.0.0:
version "1.0.0"
@@ -9610,8 +9608,8 @@ wcwidth@^1.0.0:
defaults "^1.0.3"
weasels@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/weasels/-/weasels-1.1.0.tgz#f2335da6ad8630772bc515549d010bc0415192cb"
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/weasels/-/weasels-1.1.1.tgz#3f3c72ac0a8ea19f5714a814c9101e0740857b25"
webpack-sources@^0.2.3:
version "0.2.3"
@@ -9721,7 +9719,7 @@ wreck@10.x.x:
boom "4.x.x"
hoek "4.x.x"
-wreck@12.x.x:
+wreck@12.x.x, wreck@^12.2.2:
version "12.2.2"
resolved "https://registry.yarnpkg.com/wreck/-/wreck-12.2.2.tgz#e21823d34c36d672004eefa347ae8c4f6050e3db"
dependencies:
@@ -9748,7 +9746,7 @@ write-file-stdout@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/write-file-stdout/-/write-file-stdout-0.0.2.tgz#c252d7c7c5b1b402897630e3453c7bfe690d9ca1"
-write-json-file@^2.0.0, write-json-file@^2.1.0, write-json-file@^2.2.0:
+write-json-file@^2.1.0, write-json-file@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-2.2.0.tgz#51862506bbb3b619eefab7859f1fd6c6d0530876"
dependencies:
@@ -9759,14 +9757,7 @@ write-json-file@^2.0.0, write-json-file@^2.1.0, write-json-file@^2.2.0:
sort-keys "^1.1.1"
write-file-atomic "^2.0.0"
-write-pkg@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-2.1.0.tgz#353aa44c39c48c21440f5c08ce6abd46141c9c08"
- dependencies:
- sort-keys "^1.1.2"
- write-json-file "^2.0.0"
-
-write-pkg@^3.0.1:
+write-pkg@^3.0.1, write-pkg@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-3.1.0.tgz#030a9994cc9993d25b4e75a9f1a1923607291ce9"
dependencies: