diff --git a/package.json b/package.json index a477bcabed..f2b771939c 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/packages/api/core/package.json b/packages/api/core/package.json index c064732c48..5396038e76 100644 --- a/packages/api/core/package.json +++ b/packages/api/core/package.json @@ -66,4 +66,4 @@ "engines": { "node": ">= 6.0" } -} +} \ No newline at end of file diff --git a/packages/api/core/src/api/start.ts b/packages/api/core/src/api/start.ts index 8a6d0c1bb8..01117b9395 100644 --- a/packages/api/core/src/api/start.ts +++ b/packages/api/core/src/api/start.ts @@ -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; }; diff --git a/packages/plugin/webpack/package.json b/packages/plugin/webpack/package.json index 91f506b01c..ea422d8d7f 100644 --- a/packages/plugin/webpack/package.json +++ b/packages/plugin/webpack/package.json @@ -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" } -} +} \ No newline at end of file diff --git a/packages/plugin/webpack/src/Config.ts b/packages/plugin/webpack/src/Config.ts index 4eedb1ac4e..b05adb20e2 100644 --- a/packages/plugin/webpack/src/Config.ts +++ b/packages/plugin/webpack/src/Config.ts @@ -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[]; } diff --git a/packages/plugin/webpack/src/WebpackPlugin.ts b/packages/plugin/webpack/src/WebpackPlugin.ts index a757cde5eb..95004e33c6 100644 --- a/packages/plugin/webpack/src/WebpackPlugin.ts +++ b/packages/plugin/webpack/src/WebpackPlugin.ts @@ -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 { 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 { 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 { 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 { 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 { __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 { }, 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 { 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 { 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 { - 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; } } diff --git a/packages/plugin/webpack/src/util/once.ts b/packages/plugin/webpack/src/util/once.ts new file mode 100644 index 0000000000..e47bf63f65 --- /dev/null +++ b/packages/plugin/webpack/src/util/once.ts @@ -0,0 +1,17 @@ +export default (fn1: A, fn2: B): [A, B] => { + let once = true; + let val: any; + const make = (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), + ]; +}; diff --git a/packages/utils/web-multi-logger/package.json b/packages/utils/web-multi-logger/package.json new file mode 100644 index 0000000000..a06282cdc0 --- /dev/null +++ b/packages/utils/web-multi-logger/package.json @@ -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" + } +} \ No newline at end of file diff --git a/packages/utils/web-multi-logger/src/Log.ts b/packages/utils/web-multi-logger/src/Log.ts new file mode 100644 index 0000000000..6ed4907119 --- /dev/null +++ b/packages/utils/web-multi-logger/src/Log.ts @@ -0,0 +1,3 @@ +export default class Log { + constructor(public line: string, public timestamp: Date) {} +} diff --git a/packages/utils/web-multi-logger/src/Logger.ts b/packages/utils/web-multi-logger/src/Logger.ts new file mode 100644 index 0000000000..7d536fc3d0 --- /dev/null +++ b/packages/utils/web-multi-logger/src/Logger.ts @@ -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((resolve) => { + this.server = this.app.listen(this.port, () => resolve(this.port)); + }); + } + + stop() { + if (this.server) this.server.close(); + } +} diff --git a/packages/utils/web-multi-logger/src/Tab.ts b/packages/utils/web-multi-logger/src/Tab.ts new file mode 100644 index 0000000000..c9ef6a25d9 --- /dev/null +++ b/packages/utils/web-multi-logger/src/Tab.ts @@ -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, + }; + } +} diff --git a/packages/utils/web-multi-logger/static/index.html b/packages/utils/web-multi-logger/static/index.html new file mode 100644 index 0000000000..3c397e023b --- /dev/null +++ b/packages/utils/web-multi-logger/static/index.html @@ -0,0 +1,61 @@ + + + + + + + Electron Forge Logger + + + + +
+ +
+ + + + + + + \ No newline at end of file diff --git a/packages/utils/web-multi-logger/static/main.js b/packages/utils/web-multi-logger/static/main.js new file mode 100644 index 0000000000..8b8c3b09d0 --- /dev/null +++ b/packages/utils/web-multi-logger/static/main.js @@ -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(); diff --git a/yarn.lock b/yarn.lock index 75ec47c9bb..cde74b1132 100644 --- a/yarn.lock +++ b/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"