Browse Source

Improved connection status display

update-deps
Alex Mikhalev 7 years ago
parent
commit
7a46e9d8a3
  1. 1
      .gitignore
  2. 33
      app/components/DeviceView.tsx
  3. 44
      app/sprinklers/websocket.ts
  4. 4
      app/state/web.ts
  5. 34
      common/sprinklers/ConnectionState.ts
  6. 4
      common/sprinklers/ISprinklersApi.ts
  7. 10
      common/sprinklers/SprinklersDevice.ts
  8. 1
      common/sprinklers/index.ts
  9. 43
      common/sprinklers/mqtt/index.ts
  10. 11
      common/sprinklers/schema/index.ts
  11. 7
      common/sprinklers/websocketData.ts
  12. 8
      package.json
  13. 5
      server/logging/prettyPrint.ts
  14. 6
      server/state.ts
  15. 20
      server/websocket/index.ts
  16. 203
      yarn.lock

1
.gitignore vendored

@ -5,3 +5,4 @@ npm-debug* @@ -5,3 +5,4 @@ npm-debug*
/public
.idea
.vscode
.env*

33
app/components/DeviceView.tsx

@ -4,20 +4,31 @@ import * as React from "react"; @@ -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 (
<div className={classes}>
<Icon name={connected ? "linkify" : "unlinkify"} />&nbsp;
{connected ? "Connected" : "Disconnected"}
<Icon name={connected ? "linkify" : "unlinkify"}/>&nbsp;
{connectionText}
</div>
);
}
@ -39,28 +50,28 @@ class DeviceView extends React.Component<DeviceViewProps> { @@ -39,28 +50,28 @@ class DeviceView extends React.Component<DeviceViewProps> {
}
render() {
const { id, connected, sections, programs, sectionRunner } = this.device;
const { id, connectionState, sections, programs, sectionRunner } = this.device;
return (
<Item>
<Item.Image src={require("@app/images/raspberry_pi.png")} />
<Item.Image src={require("@app/images/raspberry_pi.png")}/>
<Item.Content className="device">
<Header as="h1">
<div>Device <kbd>{id}</kbd></div>
<ConnectionState connected={connected} />
<ConnectionState connectionState={connectionState}/>
</Header>
<Item.Meta>
Raspberry Pi Grinklers Device
</Item.Meta>
<Grid>
<Grid.Column mobile={16} largeScreen={8}>
<SectionTable sections={sections} />
<SectionTable sections={sections}/>
</Grid.Column>
<Grid.Column mobile={16} largeScreen={8}>
<RunSectionForm sections={sections} />
<RunSectionForm sections={sections}/>
</Grid.Column>
</Grid>
<ProgramTable programs={programs} sections={sections} />
<SectionRunnerView sectionRunner={sectionRunner} sections={sections} />
<ProgramTable programs={programs} sections={sections}/>
<SectionRunnerView sectionRunner={sectionRunner} sections={sections}/>
</Item.Content>
</Item>
);

44
app/state/websocket.ts → app/sprinklers/websocket.ts

@ -1,20 +1,28 @@ @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -127,4 +149,8 @@ export class WebApiClient implements s.ISprinklersApi {
cb(data);
}
}
private onBrokerConnectionUpdate(data: ws.IBrokerConnectionUpdate) {
this.connectionState.serverToBroker = data.brokerConnected;
}
}

4
app/state/web.ts

@ -1,6 +1,6 @@ @@ -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 { @@ -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}`);
}

34
common/sprinklers/ConnectionState.ts

@ -0,0 +1,34 @@ @@ -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;
}
}

4
common/sprinklers/ISprinklersApi.ts

@ -1,6 +1,10 @@ @@ -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;

10
common/sprinklers/SprinklersDevice.ts

@ -1,15 +1,20 @@ @@ -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 { @@ -19,6 +24,7 @@ export abstract class SprinklersDevice {
}
abstract get id(): string;
abstract makeRequest(request: requests.Request): Promise<requests.Response>;
runProgram(opts: requests.WithProgram) {

1
common/sprinklers/index.ts

@ -5,3 +5,4 @@ export * from "./schedule"; @@ -5,3 +5,4 @@ export * from "./schedule";
export * from "./Section";
export * from "./SectionRunner";
export * from "./SprinklersDevice";
export * from "./ConnectionState";

43
common/sprinklers/mqtt/index.ts

@ -6,6 +6,7 @@ import * as s from "@common/sprinklers"; @@ -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 { @@ -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<string, MqttSprinklersDevice> = 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 { @@ -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 { @@ -116,9 +119,10 @@ interface IHandlerEntry {
const handler = (test: RegExp) =>
(target: MqttSprinklersDevice, propertyKey: string, descriptor: TypedPropertyDescriptor<IHandler>) => {
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 { @@ -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<number, ResponseCallback> = new Map();
@ -138,6 +142,16 @@ class MqttSprinklersDevice extends s.SprinklersDevice { @@ -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 { @@ -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 { @@ -242,6 +256,7 @@ class MqttSprinklersDevice extends s.SprinklersDevice {
cb(data);
}
}
/* tslint:enable:no-unused-variable */
}

11
common/sprinklers/schema/index.ts

@ -10,6 +10,15 @@ export { requests }; @@ -10,6 +10,15 @@ export { requests };
import * as common from "./common";
export * from "./common";
export const connectionState: ModelSchema<s.ConnectionState> = {
factory: (c) => new s.ConnectionState(),
props: {
clientToServer: primitive(),
serverToBroker: primitive(),
brokerToDevice: primitive(),
},
};
export const section: ModelSchema<s.Section> = {
factory: (c) => new (c.parentContext.target as s.SprinklersDevice).sectionConstructor(
c.parentContext.target, c.json.id),
@ -73,7 +82,7 @@ export const program: ModelSchema<s.Program> = { @@ -73,7 +82,7 @@ export const program: ModelSchema<s.Program> = {
};
export const sprinklersDevice = createSimpleSchema({
connected: primitive(),
connectionState: object(connectionState),
sections: list(object(section)),
sectionRunner: object(sectionRunner),
programs: list(object(program)),

7
common/sprinklers/websocketData.ts

@ -12,7 +12,12 @@ export interface IDeviceCallResponse { @@ -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";

8
package.json

@ -13,7 +13,7 @@ @@ -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 @@ @@ -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 @@ @@ -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",

5
server/logging/prettyPrint.ts

@ -46,9 +46,8 @@ function formatter(value: any) { @@ -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) { @@ -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));
}
}

6
server/state.ts

@ -6,7 +6,11 @@ export class State { @@ -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();

20
server/websocket/index.ts

@ -7,7 +7,7 @@ import * as requests from "@common/sprinklers/requests"; @@ -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) @@ -37,12 +37,24 @@ async function deviceCallRequest(socket: WebSocket, data: ws.IDeviceCallRequest)
}
export function handler(socket: WebSocket) {
const stop = autorun(() => {
const disposers = [
autorun(() => {
const json = serialize(schema.sprinklersDevice, state.device);
log.trace({ device: json });
const data = { type: "deviceUpdate", name: "grinklers", data: json };
const data: ws.IDeviceUpdate = { type: "deviceUpdate", name: "grinklers", data: json };
socket.send(JSON.stringify(data));
}, { delay: 100 });
}, { 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");

203
yarn.lock

@ -144,15 +144,6 @@ ajv@^4.9.1: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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.*: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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: @@ -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"

Loading…
Cancel
Save