diff --git a/.gitignore b/.gitignore
index 226d09c..cc0c948 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ npm-debug*
/public
.idea
.vscode
+.env*
\ No newline at end of file
diff --git a/app/components/DeviceView.tsx b/app/components/DeviceView.tsx
index 138dd7c..9d0f1d2 100644
--- a/app/components/DeviceView.tsx
+++ b/app/components/DeviceView.tsx
@@ -4,20 +4,31 @@ import * as React from "react";
import { Grid, Header, Icon, Item } from "semantic-ui-react";
import { injectState, StateBase } from "@app/state";
-import { SprinklersDevice } from "@common/sprinklers";
+import { ConnectionState as ConState, SprinklersDevice } from "@common/sprinklers";
import { ProgramTable, RunSectionForm, SectionRunnerView, SectionTable } from ".";
import "./DeviceView.scss";
-function ConnectionState({ connected, className }: { connected: boolean, className?: string }) {
+function ConnectionState({ connectionState, className }: { connectionState: ConState, className?: string }) {
+ const connected = connectionState.isConnected;
const classes = classNames({
connectionState: true,
connected: connected, /* tslint:disable-line:object-literal-shorthand */
disconnected: !connected,
}, className);
+ let connectionText: string;
+ if (connected) {
+ connectionText = "Connected";
+ } else if (connectionState.serverToBroker) {
+ connectionText = "Device Disconnected";
+ } else if (connectionState.clientToServer) {
+ connectionText = "Broker Disconnected";
+ } else {
+ connectionText = "Server Disconnected";
+ }
return (
-
- {connected ? "Connected" : "Disconnected"}
+
+ {connectionText}
);
}
@@ -39,28 +50,28 @@ class DeviceView extends React.Component {
}
render() {
- const { id, connected, sections, programs, sectionRunner } = this.device;
+ const { id, connectionState, sections, programs, sectionRunner } = this.device;
return (
-
-
+
Raspberry Pi Grinklers Device
-
+
-
+
-
-
+
+
);
diff --git a/app/state/websocket.ts b/app/sprinklers/websocket.ts
similarity index 71%
rename from app/state/websocket.ts
rename to app/sprinklers/websocket.ts
index eb60718..9ee48cb 100644
--- a/app/state/websocket.ts
+++ b/app/sprinklers/websocket.ts
@@ -1,20 +1,28 @@
import { update } from "serializr";
import logger from "@common/logger";
-import * as s from "@common/sprinklers";
+import * as s from "@common/sprinklers/index";
import * as requests from "@common/sprinklers/requests";
-import * as schema from "@common/sprinklers/schema";
+import * as schema from "@common/sprinklers/schema/index";
import { seralizeRequest } from "@common/sprinklers/schema/requests";
import * as ws from "@common/sprinklers/websocketData";
+import { autorun, observable } from "mobx";
const log = logger.child({ source: "websocket" });
-export class WebSprinklersDevice extends s.SprinklersDevice {
- readonly api: WebApiClient;
+export class WSSprinklersDevice extends s.SprinklersDevice {
+ readonly api: WebSocketApiClient;
- constructor(api: WebApiClient) {
+ constructor(api: WebSocketApiClient) {
super();
this.api = api;
+ autorun(() => {
+ this.connectionState.serverToBroker = api.connectionState.serverToBroker;
+ this.connectionState.clientToServer = api.connectionState.clientToServer;
+ if (!api.connectionState.isConnected) {
+ this.connectionState.brokerToDevice = null;
+ }
+ });
}
get id() {
@@ -26,17 +34,25 @@ export class WebSprinklersDevice extends s.SprinklersDevice {
}
}
-export class WebApiClient implements s.ISprinklersApi {
+export class WebSocketApiClient implements s.ISprinklersApi {
readonly webSocketUrl: string;
socket!: WebSocket;
- device: WebSprinklersDevice;
+ device: WSSprinklersDevice;
nextDeviceRequestId = Math.round(Math.random() * 1000000);
deviceResponseCallbacks: { [id: number]: (res: ws.IDeviceCallResponse) => void | undefined; } = {};
+ @observable connectionState: s.ConnectionState = new s.ConnectionState();
+
+ get connected(): boolean {
+ return this.connectionState.isConnected;
+ }
+
constructor(webSocketUrl: string) {
this.webSocketUrl = webSocketUrl;
- this.device = new WebSprinklersDevice(this);
+ this.device = new WSSprinklersDevice(this);
+ this.connectionState.clientToServer = false;
+ this.connectionState.serverToBroker = false;
}
start() {
@@ -83,25 +99,28 @@ export class WebApiClient implements s.ISprinklersApi {
private onOpen() {
log.info("established websocket connection");
+ this.connectionState.clientToServer = true;
}
private onClose(event: CloseEvent) {
log.info({ reason: event.reason, wasClean: event.wasClean },
"disconnected from websocket");
+ this.connectionState.clientToServer = false;
}
private onError(event: Event) {
log.error(event, "websocket error");
+ this.connectionState.clientToServer = false;
}
private onMessage(event: MessageEvent) {
- log.trace({ event }, "websocket message");
let data: ws.IServerMessage;
try {
data = JSON.parse(event.data);
} catch (err) {
return log.error({ event, err }, "received invalid websocket message");
}
+ log.trace({ data }, "websocket message");
switch (data.type) {
case "deviceUpdate":
this.onDeviceUpdate(data);
@@ -109,6 +128,9 @@ export class WebApiClient implements s.ISprinklersApi {
case "deviceCallResponse":
this.onDeviceCallResponse(data);
break;
+ case "brokerConnectionUpdate":
+ this.onBrokerConnectionUpdate(data);
+ break;
default:
log.warn({ data }, "unsupported event type received");
}
@@ -127,4 +149,8 @@ export class WebApiClient implements s.ISprinklersApi {
cb(data);
}
}
+
+ private onBrokerConnectionUpdate(data: ws.IBrokerConnectionUpdate) {
+ this.connectionState.serverToBroker = data.brokerConnected;
+ }
}
diff --git a/app/state/web.ts b/app/state/web.ts
index 7d8d234..df30e6e 100644
--- a/app/state/web.ts
+++ b/app/state/web.ts
@@ -1,6 +1,6 @@
import { MqttApiClient } from "@common/sprinklers/mqtt";
+import { WebSocketApiClient } from "../sprinklers/websocket";
import StateBase from "./StateBase";
-import { WebApiClient } from "./websocket";
const isDev = process.env.NODE_ENV === "development";
const websocketPort = isDev ? 8080 : location.port;
@@ -10,5 +10,5 @@ export class MqttApiState extends StateBase {
}
export class WebApiState extends StateBase {
- sprinklersApi = new WebApiClient(`ws://${location.hostname}:${websocketPort}`);
+ sprinklersApi = new WebSocketApiClient(`ws://${location.hostname}:${websocketPort}`);
}
diff --git a/common/sprinklers/ConnectionState.ts b/common/sprinklers/ConnectionState.ts
new file mode 100644
index 0000000..38bf6f4
--- /dev/null
+++ b/common/sprinklers/ConnectionState.ts
@@ -0,0 +1,34 @@
+import { computed, observable } from "mobx";
+
+export class ConnectionState {
+ /**
+ * Represents if a client is connected to the sprinklers3 server (eg. via websocket)
+ * Can be null if there is no client involved
+ */
+ @observable clientToServer: boolean | null = null;
+
+ /**
+ * Represents if the sprinklers3 server is connected to the broker (eg. via mqtt)
+ * Can be null if there is no broker involved
+ */
+ @observable serverToBroker: boolean | null = null;
+
+ /**
+ * Represents if the device is connected to the broker and we can communicate with it (eg. via mqtt)
+ * Can be null if there is no device involved
+ */
+ @observable brokerToDevice: boolean | null = null;
+
+ @computed get isConnected(): boolean {
+ if (this.brokerToDevice != null) {
+ return this.brokerToDevice;
+ }
+ if (this.serverToBroker != null) {
+ return this.serverToBroker;
+ }
+ if (this.clientToServer != null) {
+ return this.clientToServer;
+ }
+ return false;
+ }
+}
diff --git a/common/sprinklers/ISprinklersApi.ts b/common/sprinklers/ISprinklersApi.ts
index 07a95e2..79f44d6 100644
--- a/common/sprinklers/ISprinklersApi.ts
+++ b/common/sprinklers/ISprinklersApi.ts
@@ -1,6 +1,10 @@
+import { ConnectionState } from "./ConnectionState";
import { SprinklersDevice } from "./SprinklersDevice";
export interface ISprinklersApi {
+ readonly connectionState: ConnectionState;
+ readonly connected: boolean;
+
start(): void;
getDevice(id: string): SprinklersDevice;
diff --git a/common/sprinklers/SprinklersDevice.ts b/common/sprinklers/SprinklersDevice.ts
index 47cf139..cfeb150 100644
--- a/common/sprinklers/SprinklersDevice.ts
+++ b/common/sprinklers/SprinklersDevice.ts
@@ -1,15 +1,20 @@
-import { observable } from "mobx";
+import { computed, observable } from "mobx";
+import { ConnectionState } from "./ConnectionState";
import { Program } from "./Program";
import * as requests from "./requests";
import { Section } from "./Section";
import { SectionRunner } from "./SectionRunner";
export abstract class SprinklersDevice {
- @observable connected: boolean = false;
+ @observable connectionState: ConnectionState = new ConnectionState();
@observable sections: Section[] = [];
@observable programs: Program[] = [];
@observable sectionRunner: SectionRunner;
+ @computed get connected(): boolean {
+ return this.connectionState.isConnected;
+ }
+
sectionConstructor: typeof Section = Section;
sectionRunnerConstructor: typeof SectionRunner = SectionRunner;
programConstructor: typeof Program = Program;
@@ -19,6 +24,7 @@ export abstract class SprinklersDevice {
}
abstract get id(): string;
+
abstract makeRequest(request: requests.Request): Promise;
runProgram(opts: requests.WithProgram) {
diff --git a/common/sprinklers/index.ts b/common/sprinklers/index.ts
index b6d7175..1834ce8 100644
--- a/common/sprinklers/index.ts
+++ b/common/sprinklers/index.ts
@@ -5,3 +5,4 @@ export * from "./schedule";
export * from "./Section";
export * from "./SectionRunner";
export * from "./SprinklersDevice";
+export * from "./ConnectionState";
diff --git a/common/sprinklers/mqtt/index.ts b/common/sprinklers/mqtt/index.ts
index 22eaae6..3054ab0 100644
--- a/common/sprinklers/mqtt/index.ts
+++ b/common/sprinklers/mqtt/index.ts
@@ -6,6 +6,7 @@ import * as s from "@common/sprinklers";
import * as requests from "@common/sprinklers/requests";
import * as schema from "@common/sprinklers/schema";
import { seralizeRequest } from "@common/sprinklers/schema/requests";
+import { autorun, observable } from "mobx";
const log = logger.child({ source: "mqtt" });
@@ -16,11 +17,16 @@ interface WithRid {
export class MqttApiClient implements s.ISprinklersApi {
readonly mqttUri: string;
client!: mqtt.Client;
- connected: boolean = false;
+ @observable connectionState: s.ConnectionState = new s.ConnectionState();
devices: Map = new Map();
+ get connected(): boolean {
+ return this.connectionState.isConnected;
+ }
+
constructor(mqttUri: string) {
this.mqttUri = mqttUri;
+ this.connectionState.serverToBroker = false;
}
private static newClientId() {
@@ -29,24 +35,21 @@ export class MqttApiClient implements s.ISprinklersApi {
start() {
const clientId = MqttApiClient.newClientId();
- log.info({ clientId }, "connecting to mqtt with client id");
+ log.info({ mqttUri: this.mqttUri, clientId }, "connecting to mqtt broker with client id");
this.client = mqtt.connect(this.mqttUri, {
- clientId,
+ clientId, connectTimeout: 5000, reconnectPeriod: 5000,
});
this.client.on("message", this.onMessageArrived.bind(this));
- this.client.on("offline", () => {
- this.connected = false;
+ this.client.on("close", () => {
+ logger.warn("mqtt disconnected");
+ this.connectionState.serverToBroker = false;
});
this.client.on("error", (err) => {
log.error({ err }, "mqtt error");
});
this.client.on("connect", () => {
log.info("mqtt connected");
- this.connected = true;
- const values = this.devices.values();
- for (const device of values) {
- device.doSubscribe();
- }
+ this.connectionState.serverToBroker = true;
});
}
@@ -116,9 +119,10 @@ interface IHandlerEntry {
const handler = (test: RegExp) =>
(target: MqttSprinklersDevice, propertyKey: string, descriptor: TypedPropertyDescriptor) => {
if (typeof descriptor.value === "function") {
- (target.handlers || (target.handlers = [])).push({
+ const entry = {
test, handler: descriptor.value,
- });
+ };
+ (target.handlers || (target.handlers = [])).push(entry);
}
};
@@ -126,7 +130,7 @@ class MqttSprinklersDevice extends s.SprinklersDevice {
readonly apiClient: MqttApiClient;
readonly prefix: string;
- handlers: IHandlerEntry[] = [];
+ handlers!: IHandlerEntry[];
private nextRequestId: number = Math.floor(Math.random() * 1000000000);
private responseCallbacks: Map = new Map();
@@ -138,6 +142,16 @@ class MqttSprinklersDevice extends s.SprinklersDevice {
this.apiClient = apiClient;
this.prefix = prefix;
this.sectionRunner = new MqttSectionRunner(this);
+
+ autorun(() => {
+ const brokerConnected = apiClient.connected;
+ this.connectionState.serverToBroker = brokerConnected;
+ if (brokerConnected) {
+ this.doSubscribe();
+ } else {
+ this.connectionState.brokerToDevice = false;
+ }
+ });
}
get id(): string {
@@ -192,7 +206,7 @@ class MqttSprinklersDevice extends s.SprinklersDevice {
/* tslint:disable:no-unused-variable */
@handler(/^connected$/)
private handleConnected(payload: string) {
- this.connected = (payload === "true");
+ this.connectionState.brokerToDevice = (payload === "true");
log.trace(`MqttSprinklersDevice with prefix ${this.prefix}: ${this.connected}`);
return;
}
@@ -242,6 +256,7 @@ class MqttSprinklersDevice extends s.SprinklersDevice {
cb(data);
}
}
+
/* tslint:enable:no-unused-variable */
}
diff --git a/common/sprinklers/schema/index.ts b/common/sprinklers/schema/index.ts
index c228126..6d8b6d3 100644
--- a/common/sprinklers/schema/index.ts
+++ b/common/sprinklers/schema/index.ts
@@ -10,6 +10,15 @@ export { requests };
import * as common from "./common";
export * from "./common";
+export const connectionState: ModelSchema = {
+ factory: (c) => new s.ConnectionState(),
+ props: {
+ clientToServer: primitive(),
+ serverToBroker: primitive(),
+ brokerToDevice: primitive(),
+ },
+};
+
export const section: ModelSchema = {
factory: (c) => new (c.parentContext.target as s.SprinklersDevice).sectionConstructor(
c.parentContext.target, c.json.id),
@@ -73,7 +82,7 @@ export const program: ModelSchema = {
};
export const sprinklersDevice = createSimpleSchema({
- connected: primitive(),
+ connectionState: object(connectionState),
sections: list(object(section)),
sectionRunner: object(sectionRunner),
programs: list(object(program)),
diff --git a/common/sprinklers/websocketData.ts b/common/sprinklers/websocketData.ts
index 797f763..43f39f0 100644
--- a/common/sprinklers/websocketData.ts
+++ b/common/sprinklers/websocketData.ts
@@ -12,7 +12,12 @@ export interface IDeviceCallResponse {
data: ResponseData;
}
-export type IServerMessage = IDeviceUpdate | IDeviceCallResponse;
+export interface IBrokerConnectionUpdate {
+ type: "brokerConnectionUpdate";
+ brokerConnected: boolean;
+}
+
+export type IServerMessage = IDeviceUpdate | IDeviceCallResponse | IBrokerConnectionUpdate;
export interface IDeviceCallRequest {
type: "deviceCallRequest";
diff --git a/package.json b/package.json
index 123983d..01ffd2d 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
"start:dev-server": "NODE_ENV=development webpack-dev-server --config ./app/webpack.config.js --env dev",
"start": "NODE_ENV=development node dist/server/index.js",
"start:pretty": "yarn start | node dist/server/logging/prettyPrint.js",
- "start:nodemon": "NODE_ENV=development nodemon --exec \"node dist/server/index.js | node dist/server/logging/prettyPrint.js\"",
+ "start:nodemon": "nodemon --delay 0.5 --exec \"env NODE_ENV=development node dist/server/index.js | node dist/server/logging/prettyPrint.js\"",
"start:watch": "run-p watch:server start:nodemon",
"start:dev": "run-p start:dev-server start:watch",
"lint:app": "tslint --project app --force --format verbose",
@@ -45,7 +45,8 @@
"pino": "^4.16.1",
"postcss-cssnext": "^3.1.0",
"serializr": "^1.1.14",
- "uglify-es": "3.3.9"
+ "uglify-es": "3.3.9",
+ "ws": "^5.1.1"
},
"devDependencies": {
"@types/async": "^2.0.49",
@@ -101,8 +102,7 @@
"url-loader": "^1.0.1",
"webpack": "^4.5.0",
"webpack-cli": "^2.0.14",
- "webpack-dev-server": "^3.1.3",
- "ws": "^5.1.1"
+ "webpack-dev-server": "^3.1.3"
},
"resolutions": {
"**/@types/react": "16.3.9",
diff --git a/server/logging/prettyPrint.ts b/server/logging/prettyPrint.ts
index 0373260..a28b6fd 100644
--- a/server/logging/prettyPrint.ts
+++ b/server/logging/prettyPrint.ts
@@ -46,9 +46,8 @@ function formatter(value: any) {
if (value.msg) {
line += chalk.cyan(value.msg);
}
- line += "\n";
if (value.err) {
- line += " " + withSpaces(value.err.stack) + "\n";
+ line += "\n " + withSpaces(value.err.stack) + "\n";
} else {
line += filter(value);
}
@@ -78,7 +77,7 @@ function filter(value: any) {
for (const key of keys) {
if (filteredKeys.indexOf(key) < 0) {
- result += " " + key + ": " + withSpaces(JSON.stringify(value[key], null, 2)) + "\n";
+ result += "\n " + key + ": " + withSpaces(JSON.stringify(value[key], null, 2));
}
}
diff --git a/server/state.ts b/server/state.ts
index 191e930..7a160e1 100644
--- a/server/state.ts
+++ b/server/state.ts
@@ -6,7 +6,11 @@ export class State {
device!: SprinklersDevice;
start() {
- this.mqttClient = new mqtt.MqttApiClient("mqtt://localhost:1883");
+ const mqttUrl = process.env.MQTT_URL;
+ if (!mqttUrl) {
+ throw new Error("Must specify a MQTT_URL to connect to");
+ }
+ this.mqttClient = new mqtt.MqttApiClient(mqttUrl);
this.device = this.mqttClient.getDevice("grinklers");
this.mqttClient.start();
diff --git a/server/websocket/index.ts b/server/websocket/index.ts
index 3edf4e9..70807d6 100644
--- a/server/websocket/index.ts
+++ b/server/websocket/index.ts
@@ -7,7 +7,7 @@ import * as requests from "@common/sprinklers/requests";
import * as schema from "@common/sprinklers/schema";
import * as ws from "@common/sprinklers/websocketData";
-import {state} from "../state";
+import { state } from "../state";
async function doDeviceCallRequest(requestData: ws.IDeviceCallRequest) {
const { deviceName, data } = requestData;
@@ -37,12 +37,24 @@ async function deviceCallRequest(socket: WebSocket, data: ws.IDeviceCallRequest)
}
export function handler(socket: WebSocket) {
- const stop = autorun(() => {
- const json = serialize(schema.sprinklersDevice, state.device);
- log.trace({ device: json });
- const data = { type: "deviceUpdate", name: "grinklers", data: json };
- socket.send(JSON.stringify(data));
- }, { delay: 100 });
+ const disposers = [
+ autorun(() => {
+ const json = serialize(schema.sprinklersDevice, state.device);
+ log.trace({ device: json });
+ const data: ws.IDeviceUpdate = { type: "deviceUpdate", name: "grinklers", data: json };
+ socket.send(JSON.stringify(data));
+ }, { delay: 100 }),
+ autorun(() => {
+ const data: ws.IBrokerConnectionUpdate = {
+ type: "brokerConnectionUpdate",
+ brokerConnected: state.mqttClient.connected,
+ };
+ socket.send(JSON.stringify(data));
+ }),
+ ];
+ const stop = () => {
+ disposers.forEach((disposer) => disposer());
+ };
socket.on("message", (socketData: WebSocket.Data) => {
if (typeof socketData !== "string") {
return log.error({ type: typeof socketData }, "received invalid socket data type from client");
diff --git a/yarn.lock b/yarn.lock
index c33de13..c9da8a1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -144,15 +144,6 @@ ajv@^4.9.1:
co "^4.6.0"
json-stable-stringify "^1.0.1"
-ajv@^5.1.0:
- version "5.5.2"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
- dependencies:
- co "^4.6.0"
- fast-deep-equal "^1.0.0"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.3.0"
-
ajv@^6.1.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.4.0.tgz#d3aff78e9277549771daf0164cff48482b754fc6"
@@ -226,8 +217,8 @@ aproba@^1.0.3, aproba@^1.1.1:
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
are-we-there-yet@~1.1.2:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
dependencies:
delegates "^1.0.0"
readable-stream "^2.0.6"
@@ -434,11 +425,7 @@ aws-sign2@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
-aws-sign2@~0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
-
-aws4@^1.2.1, aws4@^1.6.0:
+aws4@^1.2.1:
version "1.7.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289"
@@ -1137,18 +1124,6 @@ boom@2.x.x:
dependencies:
hoek "2.x.x"
-boom@4.x.x:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31"
- dependencies:
- hoek "4.x.x"
-
-boom@5.x.x:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02"
- dependencies:
- hoek "4.x.x"
-
boxen@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
@@ -1693,7 +1668,7 @@ colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
-combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5:
+combined-stream@^1.0.5, combined-stream@~1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
dependencies:
@@ -1906,12 +1881,6 @@ cryptiles@2.x.x:
dependencies:
boom "2.x.x"
-cryptiles@3.x.x:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe"
- dependencies:
- boom "5.x.x"
-
crypto-browserify@^3.11.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
@@ -2589,7 +2558,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
-extend@^3.0.0, extend@~3.0.0, extend@~3.0.1:
+extend@^3.0.0, extend@~3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
@@ -2821,14 +2790,6 @@ form-data@~2.1.1:
combined-stream "^1.0.5"
mime-types "^2.1.12"
-form-data@~2.3.1:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
- dependencies:
- asynckit "^0.4.0"
- combined-stream "1.0.6"
- mime-types "^2.1.12"
-
forwarded@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
@@ -2909,8 +2870,8 @@ gauge@~2.7.3:
wide-align "^1.1.0"
gaze@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105"
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
dependencies:
globule "^1.0.0"
@@ -3068,11 +3029,11 @@ globby@^6.1.0:
pinkie-promise "^2.0.0"
globule@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.0.tgz#1dc49c6822dd9e8a2fa00ba2a295006e8664bd09"
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
dependencies:
glob "~7.1.1"
- lodash "~4.17.4"
+ lodash "~4.17.10"
minimatch "~3.0.2"
got@^6.7.1:
@@ -3156,10 +3117,6 @@ har-schema@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
-har-schema@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
-
har-validator@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d"
@@ -3176,13 +3133,6 @@ har-validator@~4.2.1:
ajv "^4.9.1"
har-schema "^1.0.5"
-har-validator@~5.0.3:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
- dependencies:
- ajv "^5.1.0"
- har-schema "^2.0.0"
-
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
@@ -3277,15 +3227,6 @@ hawk@3.1.3, hawk@~3.1.3:
hoek "2.x.x"
sntp "1.x.x"
-hawk@~6.0.2:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038"
- dependencies:
- boom "4.x.x"
- cryptiles "3.x.x"
- hoek "4.x.x"
- sntp "2.x.x"
-
he@1.1.x:
version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
@@ -3311,10 +3252,6 @@ hoek@2.x.x:
version "2.16.3"
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
-hoek@4.x.x:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb"
-
hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40"
@@ -3440,14 +3377,6 @@ http-signature@~1.1.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
-http-signature@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
- dependencies:
- assert-plus "^1.0.0"
- jsprim "^1.2.2"
- sshpk "^1.7.0"
-
https-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
@@ -3996,7 +3925,11 @@ jquery@x.*:
version "3.3.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca"
-js-base64@^2.1.8, js-base64@^2.1.9:
+js-base64@^2.1.8:
+ version "2.4.5"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.5.tgz#e293cd3c7c82f070d700fc7a1ca0a2e69f101f92"
+
+js-base64@^2.1.9:
version "2.4.3"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.3.tgz#2e545ec2b0f2957f41356510205214e98fad6582"
@@ -4307,7 +4240,11 @@ lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
-lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.4:
+lodash@^4.0.0, lodash@~4.17.10:
+ version "4.17.10"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
+
+lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0:
version "4.17.5"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
@@ -4363,7 +4300,14 @@ lowercase-keys@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
-lru-cache@^4.0.1, lru-cache@^4.1.1:
+lru-cache@^4.0.1:
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
+ dependencies:
+ pseudomap "^1.0.2"
+ yallist "^2.1.2"
+
+lru-cache@^4.1.1:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.2.tgz#45234b2e6e2f2b33da125624c4664929a0224c3f"
dependencies:
@@ -4761,18 +4705,17 @@ node-forge@0.7.1:
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.1.tgz#9da611ea08982f4b94206b3beb4cc9665f20c300"
node-gyp@^3.3.1:
- version "3.6.2"
- resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.2.tgz#9bfbe54562286284838e750eac05295853fa1c60"
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.7.0.tgz#789478e8f6c45e277aa014f3e28f958f286f9203"
dependencies:
fstream "^1.0.0"
glob "^7.0.3"
graceful-fs "^4.1.2"
- minimatch "^3.0.2"
mkdirp "^0.5.0"
nopt "2 || 3"
npmlog "0 || 1 || 2 || 3 || 4"
osenv "0"
- request "2"
+ request ">=2.9.0 <2.82.0"
rimraf "2"
semver "~5.3.0"
tar "^2.0.0"
@@ -4823,8 +4766,8 @@ node-pre-gyp@^0.6.39:
tar-pack "^3.4.0"
node-sass@^4.8.3:
- version "4.8.3"
- resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.8.3.tgz#d077cc20a08ac06f661ca44fb6f19cd2ed41debb"
+ version "4.9.0"
+ resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.0.tgz#d1b8aa855d98ed684d6848db929a20771cc2ae52"
dependencies:
async-foreach "^0.1.3"
chalk "^1.1.1"
@@ -4966,7 +4909,7 @@ number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
-oauth-sign@~0.8.1, oauth-sign@~0.8.2:
+oauth-sign@~0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
@@ -5317,10 +5260,6 @@ performance-now@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
-performance-now@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
-
pify@^2.0.0, pify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -6046,7 +5985,7 @@ q@^1.1.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
-qs@6.5.1, qs@~6.5.1:
+qs@6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
@@ -6430,34 +6369,7 @@ replace-ext@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
-request@2:
- version "2.85.0"
- resolved "https://registry.yarnpkg.com/request/-/request-2.85.0.tgz#5a03615a47c61420b3eb99b7dba204f83603e1fa"
- dependencies:
- aws-sign2 "~0.7.0"
- aws4 "^1.6.0"
- caseless "~0.12.0"
- combined-stream "~1.0.5"
- extend "~3.0.1"
- forever-agent "~0.6.1"
- form-data "~2.3.1"
- har-validator "~5.0.3"
- hawk "~6.0.2"
- http-signature "~1.2.0"
- is-typedarray "~1.0.0"
- isstream "~0.1.2"
- json-stringify-safe "~5.0.1"
- mime-types "~2.1.17"
- oauth-sign "~0.8.2"
- performance-now "^2.1.0"
- qs "~6.5.1"
- safe-buffer "^5.1.1"
- stringstream "~0.0.5"
- tough-cookie "~2.3.3"
- tunnel-agent "^0.6.0"
- uuid "^3.1.0"
-
-request@2.81.0:
+request@2.81.0, "request@>=2.9.0 <2.82.0":
version "2.81.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
dependencies:
@@ -6629,17 +6541,21 @@ rxjs@^5.4.2, rxjs@^5.5.2:
dependencies:
symbol-observable "1.0.1"
-safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+safe-buffer@5.1.1, safe-buffer@^5.1.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
+safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+
safe-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
dependencies:
ret "~0.1.10"
-safer-buffer@^2.1.0:
+safer-buffer@^2.0.2, safer-buffer@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
@@ -6910,12 +6826,6 @@ sntp@1.x.x:
dependencies:
hoek "2.x.x"
-sntp@2.x.x:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8"
- dependencies:
- hoek "4.x.x"
-
sockjs-client@1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12"
@@ -7066,13 +6976,14 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
sshpk@^1.7.0:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.1.tgz#130f5975eddad963f1d56f92b9ac6c51fa9f83eb"
+ version "1.14.2"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
dashdash "^1.12.0"
getpass "^0.1.1"
+ safer-buffer "^2.0.2"
optionalDependencies:
bcrypt-pbkdf "^1.0.0"
ecc-jsbn "~0.1.1"
@@ -7162,7 +7073,7 @@ 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.1.0, string-width@^2.1.1:
+"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
dependencies:
@@ -7187,9 +7098,9 @@ string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
-stringstream@~0.0.4, stringstream@~0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
+stringstream@~0.0.4:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72"
strip-ansi@3.0.1, strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
@@ -7412,7 +7323,7 @@ touch@^3.1.0:
dependencies:
nopt "~1.0.10"
-tough-cookie@~2.3.0, tough-cookie@~2.3.3:
+tough-cookie@~2.3.0:
version "2.3.4"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
dependencies:
@@ -8007,17 +7918,23 @@ which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
-which@1, which@^1.2.14, which@^1.2.9:
+which@1, which@^1.2.9:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ dependencies:
+ isexe "^2.0.0"
+
+which@^1.2.14:
version "1.3.0"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a"
dependencies:
isexe "^2.0.0"
wide-align@^1.1.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710"
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
dependencies:
- string-width "^1.0.2"
+ string-width "^1.0.2 || 2"
widest-line@^2.0.0:
version "2.0.0"