feat(plugin-webpack): capture logs into web ui, handle preload scripts

This commit is contained in:
Samuel Attard 2018-05-04 17:38:18 +10:00
Родитель 8ffab0b445
Коммит e800049b13
14 изменённых файлов: 617 добавлений и 85 удалений

Просмотреть файл

@ -51,6 +51,7 @@
"electron-packager": "^12.0.1",
"electron-rebuild": "^1.6.0",
"express": "^4.16.2",
"express-ws": "^3.0.0",
"form-data": "^2.1.4",
"fs-extra": "^5.0.0",
"glob": "^7.1.1",
@ -78,6 +79,7 @@
"webpack-dev-middleware": "^2.0.5",
"webpack-hot-middleware": "^2.21.0",
"webpack-merge": "^4.1.1",
"xterm": "^3.3.0",
"yarn-or-npm": "^2.0.2"
},
"devDependencies": {
@ -95,6 +97,7 @@
"@types/electron-packager": "^10.1.0",
"@types/electron-winstaller": "^2.6.1",
"@types/express": "^4.11.1",
"@types/express-ws": "^3.0.0",
"@types/fetch-mock": "^6.0.1",
"@types/form-data": "^2.2.1",
"@types/fs-extra": "^5.0.2",

Просмотреть файл

@ -66,4 +66,4 @@
"engines": {
"node": ">= 6.0"
}
}
}

Просмотреть файл

@ -65,6 +65,7 @@ export default async ({
if (typeof spawnedPluginChild === 'string') {
electronExecPath = spawnedPluginChild;
} else if (spawnedPluginChild) {
await runHook(forgeConfig, 'postStart', spawnedPluginChild);
return spawnedPluginChild;
}
@ -93,5 +94,6 @@ export default async ({
spawned = spawn(process.execPath, [electronExecPath, appPath].concat(args as string[]), spawnOpts);
});
await runHook(forgeConfig, 'postStart', spawned);
return spawned;
};

Просмотреть файл

@ -10,17 +10,16 @@
"scripts": {
"test": "exit 0"
},
"devDependencies": {
"chai": "^4.0.0",
"mocha": "^5.0.0"
},
"devDependencies": {},
"engines": {
"node": ">= 6.0"
},
"dependencies": {
"@electron-forge/async-ora": "6.0.0-beta.10",
"@electron-forge/plugin-base": "6.0.0-beta.10",
"@electron-forge/web-multi-logger": "^6.0.0-beta.10",
"cross-spawn-promise": "^0.10.1",
"debug": "^3.0.0",
"express": "^4.16.2",
"fs-extra": "^5.0.0",
"global": "^4.3.2",
@ -30,4 +29,4 @@
"webpack-hot-middleware": "^2.21.0",
"webpack-merge": "^4.1.1"
}
}
}

Просмотреть файл

@ -4,13 +4,18 @@ export interface WebpackPluginEntryPoint {
html: string;
js: string;
name: string;
prefixedEntries?: string[];
preload?: WebpackPreloadEntryPoint;
}
export interface WebpackPreloadEntryPoint {
js: string;
prefixedEntries?: string[];
}
export interface WebpackPluginRendererConfig {
config: WebpackConfiguration | string;
prefixedEntries?: string[];
entryPoints: WebpackPluginEntryPoint[];
}

Просмотреть файл

@ -1,5 +1,9 @@
import { asyncOra } from '@electron-forge/async-ora';
import PluginBase from '@electron-forge/plugin-base';
import Logger from '@electron-forge/web-multi-logger';
import Tab from '@electron-forge/web-multi-logger/dist/Tab';
import { ChildProcess } from 'child_process';
import debug from 'debug';
import fs from 'fs-extra';
import merge from 'webpack-merge';
import path from 'path';
@ -8,17 +12,23 @@ import webpack, { Configuration } from 'webpack';
import webpackHotMiddleware from 'webpack-hot-middleware';
import webpackDevMiddleware from 'webpack-dev-middleware';
import express from 'express';
import http from 'http';
import HtmlWebpackPlugin, { Config } from 'html-webpack-plugin';
import { WebpackPluginConfig, WebpackPluginEntryPoint } from './Config';
import once from './util/once';
import { WebpackPluginConfig, WebpackPluginEntryPoint, WebpackPreloadEntryPoint } from './Config';
const d = debug('electron-forge:plugin:webpack');
const BASE_PORT = 3000;
export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
name = 'webpack';
private isProd = false;
private baseDir!: string;
private watchers: webpack.Compiler.Watching[] = [];
private servers: http.Server[] = [];
private loggers: Logger[] = [];
constructor(c: WebpackPluginConfig) {
super(c);
@ -32,8 +42,35 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
return config;
}
private exitHandler = (options: { cleanup?: boolean; exit?: boolean }, err?: Error) => {
d('handling process exit with:', options);
if (options.cleanup) {
for (const watcher of this.watchers) {
d('cleaning webpack watcher');
watcher.close(() => {});
}
this.watchers = [];
for (const server of this.servers) {
d('cleaning http server');
server.close();
}
this.servers = [];
for (const logger of this.loggers) {
d('stopping logger');
logger.stop();
}
this.loggers = [];
}
if (err) console.error(err.stack);
if (options.exit) process.exit();
}
init = (dir: string) => {
this.baseDir = path.resolve(dir, '.webpack');
d('hooking process events');
process.on('exit', this.exitHandler.bind(this, { cleanup: true }));
process.on('SIGINT', this.exitHandler.bind(this, { exit: true }));
}
getHook(name: string) {
@ -44,6 +81,13 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
await this.compileMain();
await this.compileRenderers();
};
case 'postStart':
return async (_: any, child: ChildProcess) => {
console.log(child);
console.log(Object.keys(child));
d('hooking electron process exit');
child.on('exit', () => this.exitHandler({ cleanup: true, exit: true }));
};
}
return null;
}
@ -57,11 +101,21 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
const defines: { [key: string]: string; } = {};
let index = 0;
if (!this.config.renderer.entryPoints || !Array.isArray(this.config.renderer.entryPoints)) {
throw new Error('Required config option "renderer.entryPoints" has not been defined');
}
for (const entryPoint of this.config.renderer.entryPoints) {
defines[`${entryPoint.name.toUpperCase().replace(/ /g, '_')}_WEBPACK_ENTRY`] =
this.isProd
? `\`file://\$\{require('path').resolve(__dirname, '../renderer', '${entryPoint.name}', 'index.html')\}\``
: `'http://localhost:${BASE_PORT + index}'`;
if (entryPoint.preload) {
defines[`${entryPoint.name.toUpperCase().replace(/ /g, '_')}_PRELOAD_WEBPACK_ENTRY`] =
this.isProd
? `\`file://\$\{require('path').resolve(__dirname, '../renderer', '${entryPoint.name}', 'preload.js')\}\``
: `'${path.resolve(this.baseDir, 'renderer', entryPoint.name, 'preload.js')}'`;
}
index += 1;
}
return merge.smart({
@ -79,12 +133,40 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
__dirname: false,
__filename: false,
},
resolve: {
modules: [
path.resolve(path.dirname(this.baseDir), './'),
path.resolve(path.dirname(this.baseDir), 'node_modules'),
path.resolve(__dirname, '..', 'node_modules'),
],
},
}, mainConfig || {});
}
getPreloadRendererConfig = async (parentPoint: WebpackPluginEntryPoint, entryPoint: WebpackPreloadEntryPoint) => {
const rendererConfig = this.resolveConfig(this.config.renderer.config);
const prefixedEntries = entryPoint.prefixedEntries || [];
return merge.smart({
devtool: 'inline-source-map',
target: 'electron-renderer',
entry: prefixedEntries.concat([
entryPoint.js,
]),
output: {
path: path.resolve(this.baseDir, 'renderer', parentPoint.name),
filename: 'preload.js',
},
node: {
__dirname: false,
__filename: false,
},
}, rendererConfig);
}
getRendererConfig = async (entryPoint: WebpackPluginEntryPoint) => {
const rendererConfig = this.resolveConfig(this.config.renderer.config);
const prefixedEntries = this.config.renderer.prefixedEntries || [];
const prefixedEntries = entryPoint.prefixedEntries || [];
return merge.smart({
devtool: 'inline-source-map',
target: 'electron-renderer',
@ -108,18 +190,35 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
}, rendererConfig);
}
compileMain = async () => {
compileMain = async (watch = false, logger?: Logger) => {
let tab: Tab;
if (logger) {
tab = logger.createTab('Main Process');
}
await asyncOra('Compiling Main Process Code', async () => {
await new Promise(async (resolve, reject) => {
webpack(await this.getMainConfig()).run((err, stats) => {
if (err) return reject(err);
resolve();
});
const compiler = webpack(await this.getMainConfig());
const [onceResolve, onceReject] = once(resolve, reject);
const cb: webpack.ICompiler.Handler = (err, stats) => {
if (tab) {
tab.log(stats.toString({
colors: true,
}));
}
if (err) return onceReject(err);
onceResolve();
};
if (watch) {
this.watchers.push(compiler.watch({}, cb));
} else {
compiler.run(cb);
}
});
});
}
compileRenderers = async () => {
compileRenderers = async (watch = false) => {
for (const entryPoint of this.config.renderer.entryPoints) {
await asyncOra(`Compiling Renderer Template: ${entryPoint.name}`, async () => {
await new Promise(async (resolve, reject) => {
@ -128,18 +227,33 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
resolve();
});
});
if (entryPoint.preload) {
await new Promise(async (resolve, reject) => {
webpack(await this.getPreloadRendererConfig(entryPoint, entryPoint.preload!)).run((err, stats) => {
if (err) return reject(err);
resolve();
});
});
}
});
}
}
launchDevServers = async () => {
launchDevServers = async (logger: Logger) => {
await asyncOra('Launch Dev Servers', async () => {
let index = 0;
for (const entryPoint of this.config.renderer.entryPoints) {
const tab = logger.createTab(entryPoint.name);
const config = await this.getRendererConfig(entryPoint);
const compiler = webpack(config);
const server = webpackDevMiddleware(compiler, {
logLevel: 'silent',
logger: {
log: tab.log.bind(tab),
info: tab.log.bind(tab),
error: tab.log.bind(tab),
warn: tab.log.bind(tab),
},
publicPath: '/',
hot: true,
historyApiFallback: true,
@ -147,15 +261,38 @@ export default class WebpackPlugin extends PluginBase<WebpackPluginConfig> {
const app = express();
app.use(server);
app.use(webpackHotMiddleware(compiler));
app.listen(BASE_PORT + index);
this.servers.push(app.listen(BASE_PORT + index));
index += 1;
}
});
await asyncOra('Compile Preload Scripts', async () => {
for (const entryPoint of this.config.renderer.entryPoints) {
if (entryPoint.preload) {
await new Promise(async (resolve, reject) => {
const tab = logger.createTab(`${entryPoint.name} - Preload`);
const [onceResolve, onceReject] = once(resolve, reject);
const cb: webpack.ICompiler.Handler = (err, stats) => {
tab.log(stats.toString({
colors: true,
}));
if (err) return onceReject(err);
onceResolve();
};
this.watchers.push(webpack(await this.getPreloadRendererConfig(entryPoint, entryPoint.preload!)).watch({}, cb));
});
}
}
});
}
async startLogic(): Promise<false> {
await this.compileMain();
await this.launchDevServers();
const logger = new Logger();
this.loggers.push(logger);
await this.compileMain(true, logger);
await this.launchDevServers(logger);
await logger.start();
return false;
}
}

Просмотреть файл

@ -0,0 +1,17 @@
export default <A, B>(fn1: A, fn2: B): [A, B] => {
let once = true;
let val: any;
const make = <T>(fn: T): T => {
return ((...args: any[]) => {
if (once) {
val = (fn as any)(...args);
once = false;
}
return val;
}) as any as T;
};
return [
make(fn1),
make(fn2),
];
};

Просмотреть файл

@ -0,0 +1,22 @@
{
"name": "@electron-forge/web-multi-logger",
"version": "6.0.0-beta.10",
"description": "A helper utility for wrapping async functions in an ora",
"repository": "https://github.com/electron-userland/electron-forge",
"author": "Samuel Attard",
"license": "MIT",
"main": "dist/Logger.js",
"typings": "dist/Logger.d.ts",
"scripts": {
"test": "exit 0"
},
"devDependencies": {},
"dependencies": {
"express": "^4.16.2",
"express-ws": "^3.0.0",
"xterm": "^3.3.0"
},
"engines": {
"node": ">= 6.0"
}
}

Просмотреть файл

@ -0,0 +1,3 @@
export default class Log {
constructor(public line: string, public timestamp: Date) {}
}

Просмотреть файл

@ -0,0 +1,44 @@
import express from 'express';
import path from 'path';
import ews from 'express-ws';
import http from 'http';
import Tab from './Tab';
export default class Logger {
private app = express();
private ws!: ews.Instance;
private tabs: Tab[] = [];
private server: http.Server | null = null;
constructor(private port = 9000) {
this.registerRoutes();
}
registerRoutes() {
this.ws = ews(this.app);
this.app.get('/rest/tabs', (req, res) => {
return res.json(this.tabs);
});
this.app.use('/xterm', express.static(path.resolve(__dirname, '..', 'node_modules', 'xterm', 'dist')));
this.app.use(express.static(path.resolve(__dirname, '..', 'static')));
(this.app as any).ws('/sub', () => {});
}
createTab(name: string) {
const tab = new Tab(name, this.ws);
this.tabs.push(tab);
return tab;
}
start() {
return new Promise<number>((resolve) => {
this.server = this.app.listen(this.port, () => resolve(this.port));
});
}
stop() {
if (this.server) this.server.close();
}
}

Просмотреть файл

@ -0,0 +1,35 @@
import ews from 'express-ws';
import Log from './Log';
let idCounter = 1;
export default class Tab {
private logs: Log[] = [];
private id: number;
constructor(public name: string, private ws: ews.Instance) {
this.id = idCounter;
idCounter += 1;
}
log(line: string) {
const log = new Log(line, new Date());
this.logs.push(log);
for (const client of this.ws.getWss().clients) {
client.send(JSON.stringify({
tab: this.id,
payload: log,
}));
}
}
toJSON() {
return {
id: this.id,
name: this.name,
logs: this.logs,
};
}
}

Просмотреть файл

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Electron Forge Logger</title>
<link rel="stylesheet" href="/xterm/xterm.css" />
<style>
body {
padding: 0;
margin: 0;
background: #002B36;
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,"Fira Sans","Droid Sans","Helvetica Neue",sans-serif;
}
.tabs {
height: 48px;
background: #eee8d5;
display: flex;
flex-direction: row;
}
.tabs .tab {
padding: 0 16px 6px 16px;
align-items: center;
justify-content: center;
display: flex;
transition: background 0.4s ease-in-out, color 0.4s ease-in-out;
background: #eee8d5;
color: #073642;
cursor: pointer;
}
.tabs .tab:hover, .tabs .tab.selected-tab {
background: #586e75;
color: #eee8d5;
}
.tabs .tab.selected-tab {
font-weight: bold;
}
#terminal {
margin-top: 20px;
height: calc(100vh - 88px);
padding-left: 16px;
}
</style>
</head>
<body>
<div class="tabs"></div>
<div id="terminal"></div>
<script src="/xterm/xterm.js"></script>
<script src="/xterm/addons/fit/fit.js"></script>
<script src="/xterm/addons/search/search.js"></script>
<script src="/main.js"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,113 @@
Terminal.applyAddon(fit);
Terminal.applyAddon(search);
const split = (text) => {
return text.split(/\n/g);
}
class Renderer {
constructor() {
this.term = new Terminal({
cursorBlink: false,
theme: {
foreground: '#93A1A1',
background: '#002B36',
cursor: '#D30102',
cursorAccent: '#D30102',
selection: '#2AA19899',
black: '#073642',
red: '#dc322f',
green: '#859900',
yellow: '#b58900',
blue: '#268bd2',
magenta: '#d33682',
cyan: '#2aa198',
white: '#eee8d5',
brightBlack: '#586e75',
brightRed: '#cb4b16',
brightGreen: '#586e75',
brightYellow: '#657b83',
brightBlue: '#839496',
brightMagenta: '#6c71c4',
brightCyan: '#93a1a1',
brightWhite: '#fdf6e3'
}
});
this.container = document.querySelector('#terminal');
this.term.open(this.container);
this.term.fit();
window.addEventListener('resize', () => {
this.term.fit();
});
this.fetch = this.fetch.bind(this);
this.initialRender = this.initialRender.bind(this);
this.subscribe = this.subscribe.bind(this);
this.renderTabs = this.renderTabs.bind(this);
this.fetch();
}
async fetch() {
const response = await fetch('/rest/tabs');
const tabs = await response.json();
this.tabs = tabs;
this.renderTabs();
this.selectTab(tabs[0]);
this.subscribe(tabs);
}
subscribe(tabs) {
const sub = new WebSocket(`ws://localhost:${location.port}/sub`);
sub.onmessage = (message) => {
const data = JSON.parse(message.data);
const tab = tabs.find(tab => tab.id === data.tab);
if (tab) {
tab.logs.push(data.payload);
if (this.currentTab.id === tab.id) {
for (const line of split(data.payload.line)) {
this.term.writeln(line);
}
}
}
}
}
renderTabs() {
const tabsContainer = document.querySelector('.tabs');
for (const tab of this.tabs) {
const elem = document.createElement('span');
elem.innerText = tab.name;
elem.classList.add('tab');
elem.setAttribute('data-id', tab.id);
elem.addEventListener('click', () => {
this.selectTab(tab);
});
tabsContainer.appendChild(elem);
}
}
selectTab(tab) {
const selected = document.querySelector('.selected-tab');
if (selected) selected.classList.remove('selected-tab');
document.querySelector(`[data-id="${tab.id}"]`).classList.add('selected-tab');
this.currentTab = tab;
this.initialRender(tab);
}
initialRender(tab) {
this.term.clear();
for (const log of tab.logs) {
for (const line of split(log.line)) {
this.term.writeln(line);
}
}
}
}
// term.write('Hello from \033[1;3;31mxterm.js\033[0m $ ');
const r = new Renderer();

219
yarn.lock
Просмотреть файл

@ -763,7 +763,15 @@
"@types/events" "*"
"@types/node" "*"
"@types/express@^4.11.1":
"@types/express-ws@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/express-ws/-/express-ws-3.0.0.tgz#89674edba2e9141916fc4d4d30fbd4f810e6b80b"
dependencies:
"@types/express" "*"
"@types/express-serve-static-core" "*"
"@types/ws" "*"
"@types/express@*", "@types/express@^4.11.1":
version "4.11.1"
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.11.1.tgz#f99663b3ab32d04cb11db612ef5dd7933f75465b"
dependencies:
@ -1078,6 +1086,13 @@
"@types/uglify-js" "*"
source-map "^0.6.0"
"@types/ws@*":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-5.1.0.tgz#a6382c1ad2dc3a68d0650fbb4ce214ca78f2e5bf"
dependencies:
"@types/events" "*"
"@types/node" "*"
abab@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"
@ -1194,18 +1209,18 @@ 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.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
dependencies:
color-convert "^1.9.0"
ansi-styles@^3.2.1:
ansi-styles@^3.2.0, ansi-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
dependencies:
color-convert "^1.9.0"
ansi-to-html@^0.6.4:
version "0.6.4"
resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.4.tgz#8b14ace87f8b3d25367d03cd5300d60be17cf9e0"
dependencies:
entities "^1.1.1"
anymatch@^1.3.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
@ -1469,10 +1484,14 @@ 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.6.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
aws4@^1.6.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289"
babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@ -1975,7 +1994,7 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0:
chalk@^2.0.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
dependencies:
@ -1983,17 +2002,17 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0:
escape-string-regexp "^1.0.5"
supports-color "^5.2.0"
chalk@^2.3.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52"
chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@^2.3.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
chalk@^2.3.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52"
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
@ -2119,11 +2138,7 @@ cli-cursor@^2.1.0:
dependencies:
restore-cursor "^2.0.0"
cli-spinners@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.1.0.tgz#f1847b168844d917a671eb9d147e3df497c90d06"
cli-spinners@^1.1.0:
cli-spinners@^1.0.1, cli-spinners@^1.1.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a"
@ -2204,8 +2219,8 @@ colors@1.0.x:
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
colors@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
version "1.2.3"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.3.tgz#1b152a9c4f6c9f74bc4bb96233ad0b7983b79744"
colors@^1.2.0:
version "1.2.1"
@ -3413,6 +3428,12 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2:
dependencies:
homedir-polyfill "^1.0.1"
express-ws@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/express-ws/-/express-ws-3.0.0.tgz#7ddaaf3b7c758865c099905989911b6234477dbd"
dependencies:
ws "^2.0.0"
express@^4.16.2:
version "4.16.3"
resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53"
@ -3522,8 +3543,8 @@ eyes@0.1.x:
resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0"
fast-deep-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
version "1.1.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
@ -4294,8 +4315,8 @@ homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
parse-passwd "^1.0.0"
hosted-git-info@^2.1.4:
version "2.5.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c"
version "2.6.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.6.0.tgz#23235b29ab230c576aab0d4f13fc046b0b038222"
html-entities@^1.2.0:
version "1.2.1"
@ -5530,7 +5551,13 @@ mime-db@~1.33.0:
version "1.33.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
mime-types@^2.1.12, mime-types@^2.1.17, mime-types@~2.1.17, mime-types@~2.1.7:
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18:
version "2.1.18"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
dependencies:
mime-db "~1.33.0"
mime-types@^2.1.17, mime-types@~2.1.7:
version "2.1.17"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
dependencies:
@ -5540,12 +5567,6 @@ mime-types@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce"
mime-types@~2.1.18:
version "2.1.18"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
dependencies:
mime-db "~1.33.0"
mime@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
@ -5737,8 +5758,8 @@ no-case@^2.2.0:
lower-case "^1.1.1"
node-abi@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.2.0.tgz#e802ac7a2408e2c0593fb3176ffdf8a99a9b4dec"
version "2.4.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.4.0.tgz#3c27515cb842f5bbc132a31254f9f1e1c55c7b83"
dependencies:
semver "^5.4.1"
@ -6528,7 +6549,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"
@ -6540,6 +6561,10 @@ qs@~6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
qs@~6.5.1:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
querystring-es3@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
@ -6658,7 +6683,7 @@ readable-stream@^1.1.8, readable-stream@~1.1.9:
isarray "0.0.1"
string_decoder "~0.10.x"
readable-stream@^2.0.1, readable-stream@^2.3.3:
readable-stream@^2.0.1, readable-stream@^2.0.6, readable-stream@^2.3.3:
version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
dependencies:
@ -6670,7 +6695,7 @@ readable-stream@^2.0.1, readable-stream@^2.3.3:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2:
readable-stream@^2.0.2, readable-stream@^2.1.4, readable-stream@^2.2.2:
version "2.3.4"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.4.tgz#c946c3f47fa7d8eabc0b6150f4a12f69a4574071"
dependencies:
@ -6819,9 +6844,9 @@ replace-comments-x@^2.0.0:
require-coercible-to-string-x "^1.0.0"
to-string-x "^1.4.2"
request@2, request@^2.45.0, request@^2.55.0, request@^2.79.0:
version "2.83.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356"
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"
@ -6894,6 +6919,33 @@ request@2.81.0:
tunnel-agent "^0.6.0"
uuid "^3.0.0"
request@^2.45.0, request@^2.55.0, request@^2.79.0:
version "2.83.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356"
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"
require-coercible-to-string-x@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/require-coercible-to-string-x/-/require-coercible-to-string-x-1.0.0.tgz#367b3e9ca67e00324c411b0b498453a74cd5569e"
@ -7016,7 +7068,13 @@ rx@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
rxjs@^5.1.1, rxjs@^5.5.2:
rxjs@^5.1.1:
version "5.5.10"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.10.tgz#fde02d7a614f6c8683d0d1957827f492e09db045"
dependencies:
symbol-observable "1.0.1"
rxjs@^5.5.2:
version "5.5.6"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.6.tgz#e31fb96d6fd2ff1fd84bcea8ae9c02d007179c02"
dependencies:
@ -7036,14 +7094,18 @@ s3@^4.4.0:
rimraf "~2.2.8"
streamsink "~1.2.0"
safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
safe-buffer@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
safe-buffer@^5.1.0:
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:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
safe-buffer@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
samsam@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50"
@ -7340,19 +7402,27 @@ spawn-wrap@^1.4.2:
signal-exit "^3.0.2"
which "^1.3.0"
spdx-correct@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
spdx-correct@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82"
dependencies:
spdx-license-ids "^1.0.2"
spdx-expression-parse "^3.0.0"
spdx-license-ids "^3.0.0"
spdx-expression-parse@~1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
spdx-exceptions@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9"
spdx-license-ids@^1.0.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
spdx-expression-parse@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
dependencies:
spdx-exceptions "^2.1.0"
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87"
speedometer@~0.1.2:
version "0.1.4"
@ -7381,8 +7451,8 @@ 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.13.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3"
version "1.14.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.1.tgz#130f5975eddad963f1d56f92b9ac6c51fa9f83eb"
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
@ -7547,13 +7617,13 @@ supports-color@^4.2.1:
dependencies:
has-flag "^2.0.0"
supports-color@^5.1.0, supports-color@^5.2.0:
supports-color@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a"
dependencies:
has-flag "^3.0.0"
supports-color@^5.3.0:
supports-color@^5.2.0, supports-color@^5.3.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
dependencies:
@ -7813,12 +7883,18 @@ touch@^3.1.0:
dependencies:
nopt "~1.0.10"
tough-cookie@>=0.12.0, tough-cookie@^2.2.0, tough-cookie@~2.3.0, tough-cookie@~2.3.3:
tough-cookie@>=0.12.0, tough-cookie@^2.2.0, tough-cookie@~2.3.0:
version "2.3.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561"
dependencies:
punycode "^1.4.1"
tough-cookie@~2.3.3:
version "2.3.4"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
dependencies:
punycode "^1.4.1"
tr46@~0.0.1:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
@ -8043,6 +8119,10 @@ uid-number@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
ultron@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
undefsafe@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76"
@ -8231,11 +8311,11 @@ uuid@^3.0.0, uuid@^3.1.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
validate-npm-package-license@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
version "3.0.3"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338"
dependencies:
spdx-correct "~1.0.0"
spdx-expression-parse "~1.0.0"
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
validate.io-undefined@^1.0.3:
version "1.0.3"
@ -8450,6 +8530,13 @@ write-file-atomic@^2.0.0:
imurmurhash "^0.1.4"
signal-exit "^3.0.2"
ws@^2.0.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-2.3.1.tgz#6b94b3e447cb6a363f785eaf94af6359e8e81c80"
dependencies:
safe-buffer "~5.0.1"
ultron "~1.1.0"
xdg-basedir@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
@ -8499,6 +8586,10 @@ xtend@~2.1.1:
dependencies:
object-keys "~0.4.0"
xterm@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.3.0.tgz#b09a19fc2cd5decd21112e5c9dab0b61991f6cf3"
y18n@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"