Very rough go at connecting to socket and rendering console data for server

This commit is contained in:
Dane Everitt 2018-07-20 23:45:07 -07:00
parent 784c73becd
commit 8db9d9bbee
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
9 changed files with 311 additions and 114 deletions

View file

@ -0,0 +1,48 @@
<?php
namespace Pterodactyl\Http\Controllers\Server;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Pterodactyl\Http\Controllers\Controller;
use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService;
class CredentialsController extends Controller
{
/**
* @var \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService
*/
private $keyProviderService;
/**
* CredentialsController constructor.
*
* @param \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService $keyProviderService
*/
public function __construct(DaemonKeyProviderService $keyProviderService)
{
$this->keyProviderService = $keyProviderService;
}
/**
* Return a set of credentials that the currently authenticated user can use to access
* a given server with.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function index(Request $request): JsonResponse
{
/** @var \Pterodactyl\Models\Server $server */
$server = $request->attributes->get('server');
$server->loadMissing('node');
return JsonResponse::create([
'node' => $server->getRelation('node')->getConnectionAddress(),
'key' => $this->keyProviderService->handle($server, $request->user()),
]);
}
}

View file

@ -131,6 +131,16 @@ class Node extends Model implements CleansAttributes, ValidableContract
'maintenance_mode' => false,
];
/**
* Get the connection address to use when making calls to this node.
*
* @return string
*/
public function getConnectionAddress(): string
{
return sprintf('%s://%s:%s', $this->scheme, $this->fqdn, $this->daemonListen);
}
/**
* Returns the configuration in JSON format.
*

View file

@ -2,6 +2,7 @@
"name": "pterodactyl-panel",
"dependencies": {
"date-fns": "^1.29.0",
"socket.io-client": "^2.1.1",
"vee-validate": "^2.1.0-beta.2",
"vue": "^2.5.7",
"vue-axios": "^2.1.1",

View file

@ -69,6 +69,8 @@
import {mapState} from 'vuex';
import { ConsolePage } from './subpages/ConsolePage';
import io from 'socket.io-client';
export default {
components: {
ProgressBar, Navigation, ConsolePage, TerminalIcon, FolderIcon, UsersIcon,
@ -76,7 +78,7 @@
},
computed: {
...mapState('server', ['server']),
...mapState('server', ['server', 'credentials']),
},
mounted: function () {
@ -85,20 +87,70 @@
data: function () {
return {
socket: null,
loadingServerData: true,
};
},
methods: {
/**
* Load the core server information needed for these pages to be functional.
*/
loadServer: function () {
this.$store.dispatch('server/getServer', {server: this.$route.params.id})
Promise.all([
this.$store.dispatch('server/getServer', {server: this.$route.params.id}),
this.$store.dispatch('server/getCredentials', {server: this.$route.params.id})
])
.then(() => {
this.loadingServerData = false;
this.initalizeWebsocket();
})
.catch(err => {
console.error(err);
});
.catch(console.error);
},
}
initalizeWebsocket: function () {
this.$store.commit('server/CONSOLE_DATA', 'Connecting to ' + this.credentials.node + '...');
this.socket = io(this.credentials.node + '/v1/ws/' + this.server.uuid, {
query: 'token=' + this.credentials.key,
});
this.socket.on('error', this._socket_error);
this.socket.on('connect', this._socket_connect);
this.socket.on('status', this._socket_status);
this.socket.on('initial status', this._socket_status);
this.socket.on('server log', this._socket_serverLog);
this.socket.on('console', this._socket_consoleLine);
},
_socket_error: function (err) {
this.$store.commit('server/CONSOLE_DATA', 'There was a socket error: ' + err);
console.error('there was a socket error:', err);
},
_socket_connect: function () {
this.$store.commit('server/CONSOLE_DATA', 'Connected to socket.');
this.socket.emit('send server log');
console.log('connected');
},
_socket_status: function (data) {
this.$store.commit('server/CONSOLE_DATA', 'Server state has changed.');
console.warn(data);
},
_socket_serverLog: function (data) {
data.split(/\n/g).forEach(item => {
this.$store.commit('server/CONSOLE_DATA', item);
});
},
_socket_consoleLine: function (data) {
if(data.line) {
data.line.split(/\n/g).forEach((item) => {
this.$store.commit('server/CONSOLE_DATA', item);
});
}
}
},
}
</script>

View file

@ -1,8 +1,8 @@
<template>
<div>
<div class="text-xs font-mono">
<div class="rounded-t p-2 bg-black text-grey-lightest h-48">
<div class="rounded-t p-2 bg-black text-grey-lightest overflow-scroll" style="min-height: 16rem;max-height:32rem;">
<span class="block" v-for="line in console">{{line}}</span>
</div>
<div class="rounded-b p-2 bg-grey-darkest text-white">$</div>
</div>
@ -10,9 +10,15 @@
</template>
<script>
import {mapState} from 'vuex';
export default {
name: 'console-page',
computed: {
...mapState('server', ['console']),
},
data: function () {
return {
lines: [],

File diff suppressed because one or more lines are too long

View file

@ -1,10 +1,11 @@
import route from '../../../../../vendor/tightenco/ziggy/src/js/route';
import Server from '../../models/server';
export default {
namespaced: true,
state: {
server: {},
credentials: {node: '', key: ''},
console: [],
},
getters: {
},
@ -34,10 +35,44 @@ export default {
.catch(reject);
});
},
/**
* Get authentication credentials that the client should use when connecting to the daemon to
* retrieve server information.
*
* @param commit
* @param {String} server
* @returns {Promise<any>}
*/
getCredentials: ({commit}, {server}) => {
return new Promise((resolve, reject) => {
window.axios.get(route('server.credentials', {server}))
.then(response => {
// If there is a 302 redirect or some other odd behavior (basically, response that isnt
// in JSON format) throw an error and don't try to continue with the login.
if (!(response.data instanceof Object)) {
return reject(new Error('An error was encountered while processing this request.'));
}
if (response.data.key) {
commit('SERVER_CREDENTIALS', response.data)
}
return resolve();
})
.catch(reject);
});
},
},
mutations: {
SERVER_DATA: function (state, data) {
state.server = data;
}
},
SERVER_CREDENTIALS: function (state, credentials) {
state.credentials = credentials;
},
CONSOLE_DATA: function (state, data) {
state.console.push(data);
},
},
}

View file

@ -6,104 +6,4 @@
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
Route::get('/', 'ConsoleController@index')->name('server.index');
Route::get('/console', 'ConsoleController@console')->name('server.console');
/*
|--------------------------------------------------------------------------
| Server Settings Controller Routes
|--------------------------------------------------------------------------
|
| Endpoint: /server/{server}/settings
|
*/
Route::group(['prefix' => 'settings'], function () {
Route::get('/allocation', 'Settings\AllocationController@index')->name('server.settings.allocation');
Route::get('/name', 'Settings\NameController@index')->name('server.settings.name');
Route::get('/sftp', 'Settings\SftpController@index')->name('server.settings.sftp');
Route::get('/startup', 'Settings\StartupController@index')->name('server.settings.startup');
Route::patch('/allocation', 'Settings\AllocationController@update');
Route::patch('/name', 'Settings\NameController@update');
Route::patch('/startup', 'Settings\StartupController@update');
});
/*
|--------------------------------------------------------------------------
| Server Database Controller Routes
|--------------------------------------------------------------------------
|
| Endpoint: /server/{server}/databases
|
*/
Route::group(['prefix' => 'databases'], function () {
Route::get('/', 'DatabaseController@index')->name('server.databases.index');
Route::post('/new', 'DatabaseController@store')->name('server.databases.new');
Route::patch('/password', 'DatabaseController@update')->middleware('server..database')->name('server.databases.password');
Route::delete('/delete/{database}', 'DatabaseController@delete')->middleware('server..database')->name('server.databases.delete');
});
/*
|--------------------------------------------------------------------------
| Server File Manager Controller Routes
|--------------------------------------------------------------------------
|
| Endpoint: /server/{server}/files
|
*/
Route::group(['prefix' => 'files'], function () {
Route::get('/', 'Files\FileActionsController@index')->name('server.files.index');
Route::get('/add', 'Files\FileActionsController@create')->name('server.files.add');
Route::get('/edit/{file}', 'Files\FileActionsController@view')->name('server.files.edit')->where('file', '.*');
Route::get('/download/{file}', 'Files\DownloadController@index')->name('server.files.edit')->where('file', '.*');
Route::post('/directory-list', 'Files\RemoteRequestController@directory')->name('server.files.directory-list');
Route::post('/save', 'Files\RemoteRequestController@store')->name('server.files.save');
});
/*
|--------------------------------------------------------------------------
| Server Subuser Controller Routes
|--------------------------------------------------------------------------
|
| Endpoint: /server/{server}/users
|
*/
Route::group(['prefix' => 'users'], function () {
Route::get('/', 'SubuserController@index')->name('server.subusers');
Route::get('/new', 'SubuserController@create')->name('server.subusers.new');
Route::post('/new', 'SubuserController@store');
Route::group(['middleware' => 'server..subuser'], function () {
Route::get('/view/{subuser}', 'SubuserController@view')->name('server.subusers.view');
Route::patch('/view/{subuser}', 'SubuserController@update');
Route::delete('/view/{subuser}', 'SubuserController@delete');
});
});
/*
|--------------------------------------------------------------------------
| Server Task Controller Routes
|--------------------------------------------------------------------------
|
| Endpoint: /server/{server}/tasks
|
*/
Route::group(['prefix' => 'schedules'], function () {
Route::get('/', 'Tasks\TaskManagementController@index')->name('server.schedules');
Route::get('/new', 'Tasks\TaskManagementController@create')->name('server.schedules.new');
Route::post('/new', 'Tasks\TaskManagementController@store');
Route::group(['middleware' => 'server..schedule'], function () {
Route::get('/view/{schedule}', 'Tasks\TaskManagementController@view')->name('server.schedules.view');
Route::patch('/view/{schedule}', 'Tasks\TaskManagementController@update');
Route::post('/view/{schedule}/toggle', 'Tasks\ActionController@toggle')->name('server.schedules.toggle');
Route::post('/view/{schedule}/trigger', 'Tasks\ActionController@trigger')->name('server.schedules.trigger');
Route::delete('/view/{schedule}', 'Tasks\TaskManagementController@delete');
});
});
Route::get('/credentials', 'CredentialsController@index')->name('server.credentials');

149
yarn.lock
View file

@ -805,6 +805,10 @@ acorn@^5.0.0:
version "5.6.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.6.1.tgz#c9e50c3e3717cf897f1b071ceadbb543bbc0a8d4"
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
ajv-keywords@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a"
@ -947,6 +951,10 @@ array-unique@^0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
arraybuffer.slice@~0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
@ -1213,6 +1221,10 @@ babylon@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
backo2@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
@ -1221,6 +1233,10 @@ balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
base64-arraybuffer@0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
base64-js@^1.0.2:
version "1.3.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
@ -1237,6 +1253,12 @@ base@^0.11.1:
mixin-deep "^1.2.0"
pascalcase "^0.1.1"
better-assert@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
dependencies:
callsite "1.0.0"
big.js@^3.1.3:
version "3.2.0"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
@ -1245,6 +1267,10 @@ binary-extensions@^1.0.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205"
blob@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921"
bluebird@^3.1.1, bluebird@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
@ -1425,6 +1451,10 @@ cache-base@^1.0.1:
union-value "^1.0.0"
unset-value "^1.0.0"
callsite@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
camel-case@3.0.x:
version "3.0.0"
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
@ -1741,10 +1771,18 @@ commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
component-emitter@^1.2.1:
component-bind@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
component-emitter@1.2.1, component-emitter@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
component-inherit@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -2051,7 +2089,7 @@ de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
debug@*, debug@^3.1.0:
debug@*, debug@^3.1.0, debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
@ -2246,6 +2284,32 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
engine.io-client@~3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36"
dependencies:
component-emitter "1.2.1"
component-inherit "0.0.3"
debug "~3.1.0"
engine.io-parser "~2.1.1"
has-cors "1.1.0"
indexof "0.0.1"
parseqs "0.0.5"
parseuri "0.0.5"
ws "~3.3.1"
xmlhttprequest-ssl "~1.5.4"
yeast "0.1.2"
engine.io-parser@~2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196"
dependencies:
after "0.8.2"
arraybuffer.slice "~0.0.7"
base64-arraybuffer "0.1.5"
blob "0.0.4"
has-binary2 "~1.0.2"
enhanced-resolve@^3.4.0:
version "3.4.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
@ -2807,6 +2871,16 @@ has-ansi@^2.0.0:
dependencies:
ansi-regex "^2.0.0"
has-binary2@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
dependencies:
isarray "2.0.1"
has-cors@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
has-flag@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
@ -3327,6 +3401,10 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isarray@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@ -4112,6 +4190,10 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
object-component@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
object-copy@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
@ -4301,6 +4383,18 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
dependencies:
better-assert "~1.0.0"
parseuri@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
dependencies:
better-assert "~1.0.0"
parseurl@^1.3.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
@ -5555,6 +5649,33 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
socket.io-client@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f"
dependencies:
backo2 "1.0.2"
base64-arraybuffer "0.1.5"
component-bind "1.0.0"
component-emitter "1.2.1"
debug "~3.1.0"
engine.io-client "~3.2.0"
has-binary2 "~1.0.2"
has-cors "1.1.0"
indexof "0.0.1"
object-component "0.0.3"
parseqs "0.0.5"
parseuri "0.0.5"
socket.io-parser "~3.2.0"
to-array "0.1.4"
socket.io-parser@~3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077"
dependencies:
component-emitter "1.2.1"
debug "~3.1.0"
isarray "2.0.1"
sort-keys@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
@ -5867,6 +5988,10 @@ tmp@^0.0.33:
dependencies:
os-tmpdir "~1.0.2"
to-array@0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
to-arraybuffer@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
@ -5980,6 +6105,10 @@ uglifyjs-webpack-plugin@^1.2.4, uglifyjs-webpack-plugin@^1.2.5:
webpack-sources "^1.1.0"
worker-farm "^1.5.2"
ultron@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c"
unicode-canonical-property-names-ecmascript@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.3.tgz#f6119f417467593c0086357c85546b6ad5abc583"
@ -6554,10 +6683,22 @@ ws@^4.0.0:
async-limiter "~1.0.0"
safe-buffer "~5.1.0"
ws@~3.3.1:
version "3.3.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
dependencies:
async-limiter "~1.0.0"
safe-buffer "~5.1.0"
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"
xmlhttprequest-ssl@~1.5.4:
version "1.5.5"
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
xtend@^4.0.0, xtend@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
@ -6662,3 +6803,7 @@ yargs@~3.10.0:
cliui "^2.1.0"
decamelize "^1.0.0"
window-size "0.1.0"
yeast@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"