Merge branch 'service-testing'

stable
Bronwen 2021-04-01 23:22:16 -04:00
parent 9d4697d8d6
commit 301e3eacea
17 changed files with 624 additions and 159 deletions

View File

@ -1,26 +0,0 @@
(async () => {
const { title } = require('../lib/title');
const net = require('net');
const os = require('os');
const log = require('signale');
const { config } = require('./../package.json');
const { hri } = require('human-readable-ids');
const { Profiles } = require('../lib/Profiles');
const profiles = new Profiles('client');
const yargs = require('yargs').argv;
const identity = yargs.profile ?
await profiles.get(yargs.profile) :
await profiles.get((await profiles.all())[0]);
// const id = hri.random();
// console.log(id)
// title(id);
// title(identity.name.replace(/-/g, ' '));
// await profiles.create();
})();

136
lib/Gateway.js 100644
View File

@ -0,0 +1,136 @@
const { config } = require('./config');
const Keyv = require('keyv');
const { KeyvFile } = require('keyv-file');
const { Signale } = require('signale');
const log = new Signale().scope('GTWY');
const interactive = new Signale({ interactive: true, scope: 'GTWY' });
const stp = require('./STP');
const appdata = require('./appdata');
class Gateway {
constructor(identity, endpoints) {
this.identity = identity;
this.endpoints = new Keyv({
store: new KeyvFile({
filename: `${appdata}/valnet/relay/${this.identity.name}-endpoints.json`
})
});
this.ready = this.insertEndpoints(endpoints)
.then(this.networkTest.bind(this));
}
async insertEndpoints(endpoints) {
for (const endpoint of endpoints) {
const storeValue = await this.endpoints.get(endpoint);
if (storeValue) continue;
const [host, port] = endpoint.split(':');
const record = new EndpointRecord(host, port, null, 'unknown');
const currentEnpoints = await this.endpoints.get('cache') || [];
if (currentEnpoints.indexOf(endpoint) === -1) {
currentEnpoints.push(endpoint);
await this.endpoints.set('cache', currentEnpoints);
}
await this.endpoints.set(endpoint, record);
}
log.info('gateway endpoints:');
log.info('\t' + (await this.endpoints.get('cache')).join('\n\t'));
}
async networkTest() {
const endpoints = (await Promise.all(
(await this.endpoints.get('cache'))
.map(endpoint => this.endpoints.get(endpoint))
)).map(EndpointRecord.fromJson);
for (const endpoint of endpoints) {
await this.testEndpoint(endpoint.host, endpoint.port);
}
}
async testEndpoint(host, port) {
await new Promise(async (res, rej) => {
let pings = [];
let maxPings = 10;
let connectionAttempts = 0;
log.info(`Connecting to ${host}:${port}...`);
while (connectionAttempts < 10 && pings.length < maxPings) {
await new Promise(async (res) => {
const client = stp.connect({
identity: this.identity,
ip: host,
port: parseInt(port)
});
client.on('error', _ => _);
client.on('ready', async () => {
while (pings.length < maxPings) {
interactive.info(`[${pings.length + 1}/${maxPings}] Testing connection...`);
pings.push(await client.ping());
// pings.push(10);
await new Promise(res => setTimeout(res, 100));
}
const average = Math.round(pings.reduce((a, v) => a + v, 0) / maxPings);
interactive.success(`Test complete. Average Ping: ${average}`)
client.tcpSocket.destroy();
res();
});
client.on('close', () => {
res();
});
});
}
});
}
}
class EndpointRecord {
/**
* @param {Object|string} json string / object representation
* @returns {EndpointRecord}
*/
static fromJson(obj) {
if (typeof obj === 'string')
return EndpointRecord.fromJson(JSON.parse(obj));
return new EndpointRecord(
obj.host,
obj.port,
obj.lastPing ? new PingRecord(
obj.lastPing.average,
obj.lastPing.tests,
obj.lastPing.date
) : null,
obj.status
);
}
constructor(host, port, lastPing, status) {
this.host = host;
this.port = port;
this.lastPing = lastPing;
this.status = status;
}
}
class PingRecord {
constructor(average, tests, date) {
this.average = average;
this.tests = tests;
this.date = date;
}
}
module.exports = Gateway

View File

@ -4,6 +4,7 @@ const { hri } = require('human-readable-ids');
const os = require('os'); const os = require('os');
const NodeRSA = require('node-rsa'); const NodeRSA = require('node-rsa');
let log = require('signale').scope('Identity(null)'); let log = require('signale').scope('Identity(null)');
const appdata = require('./appdata');
module.exports.Identity = class Identity { module.exports.Identity = class Identity {
kv; kv;
@ -13,9 +14,10 @@ module.exports.Identity = class Identity {
/// ASYNC CONSTRUCTOR /// ASYNC CONSTRUCTOR
constructor(module, id) { constructor(module, id) {
return new Promise(async (res, rej) => { return new Promise(async (res, rej) => {
const kv = new Keyv({ const kv = new Keyv({
store: new KeyvFile({ store: new KeyvFile({
filename: `${os.tmpdir()}/valnet/${module}/${id}.json` filename: `${appdata}/valnet/${module}/${id}.json`
}) })
}); });
@ -67,6 +69,6 @@ module.exports.Identity = class Identity {
} }
toString() { toString() {
return `[Identity(${this.name})]`; return `[Identity ${this.name}]`;
} }
} }

View File

@ -1,12 +1,13 @@
const net = require('net'); const net = require('net');
const EventEmitter = require('events'); const EventEmitter = require('events');
const NodeRSA = require('node-rsa'); const NodeRSA = require('node-rsa');
const log = require('signale').scope('stp'); const log = require('signale').scope('_STP');
const { const {
KeyExchangePacket, KeyExchangePacket,
AckPacket AckPacket,
PingPacket,
PongPacket
} = require('./packets'); } = require('./packets');
const { rejects } = require('assert');
module.exports.createServer = function({identity = {}, port = 5000} = {}, cb = _ => _) { module.exports.createServer = function({identity = {}, port = 5000} = {}, cb = _ => _) {
const server = new Server(identity, port); const server = new Server(identity, port);
@ -37,7 +38,7 @@ class Server extends EventEmitter {
} }
openServer() { openServer() {
log.info(`opening STP server on ${this.port}`); // log.info(`opening STP server on ${this.port}`);
this.tcpServer = net.createServer(this.tcpConnectClient.bind(this)); this.tcpServer = net.createServer(this.tcpConnectClient.bind(this));
this.tcpServer.on('error', e => { this.tcpServer.on('error', e => {
log.warn(e) log.warn(e)
@ -56,11 +57,17 @@ class Server extends EventEmitter {
class STPSocket extends EventEmitter { class STPSocket extends EventEmitter {
tcpSocket; tcpSocket;
readyState = 0;
buffer = ''; buffer = '';
externalKey; externalKey;
identity; identity;
CONNECTING = Symbol('connecting');
EXCHANGE = Symbol('exchange');
SECURED = Symbol('secured');
readyState = this.CONNECTING;
pingCallbacks = new Map();
get loopback() { get loopback() {
return this.identity.publicKey === return this.identity.publicKey ===
this.externalKey.exportKey('pkcs8-public-pem'); this.externalKey.exportKey('pkcs8-public-pem');
@ -113,24 +120,33 @@ class STPSocket extends EventEmitter {
} }
processMessage(obj) { processMessage(obj) {
switch(obj.cmd) {
case 'KEY': { if(this.readyState === this.CONNECTING && obj.cmd === 'KEY') {
if(this.readyState === 0) { this.externalKey = new NodeRSA();
this.externalKey = new NodeRSA(); this.externalKey.importKey(obj.data.key, 'pkcs8-public-pem');
this.externalKey.importKey(obj.data.key, 'pkcs8-public-pem'); this.tcpSocket.write(new AckPacket().toBuffer());
this.tcpSocket.write(new AckPacket().toBuffer()); this.readyState = this.EXCHANGE;
this.readyState = 1; return;
}
break;
}
case 'ACK': {
if(this.readyState === 1) {
this.readyState = 2;
this.emit('ready');
}
break;
}
} }
if(this.readyState === this.EXCHANGE && obj.cmd === 'ACK') {
this.readyState = this.SECURED;
this.emit('ready');
return;
}
if (this.readyState === this.SECURED && obj.cmd === 'PING') {
this.tcpSocket.write(new PongPacket(obj.data.id).toBuffer());
return;
}
if (this.readyState === this.SECURED && obj.cmd === 'PONG') {
if (this.pingCallbacks.has(obj.data.id)) {
this.pingCallbacks.get(obj.data.id)();
}
return;
}
} }
handshake() { handshake() {
@ -139,4 +155,17 @@ class STPSocket extends EventEmitter {
const buffer = packet.toBuffer(); const buffer = packet.toBuffer();
this.tcpSocket.write(buffer); this.tcpSocket.write(buffer);
} }
async ping() {
const startTime = new Date().getTime();
return await new Promise(async (res) => {
const packet = new PingPacket();
this.pingCallbacks.set(packet.data.id, _ => {
res(new Date().getTime() - startTime);
this.pingCallbacks.delete(packet.data.id);
});
this.tcpSocket.write(packet.toBuffer());
})
}
} }

View File

@ -1,4 +1,6 @@
const md5 = require('md5');
// #region === [ private lib functions ] ===
class STPPacket { class STPPacket {
cmd = 'NOOP'; cmd = 'NOOP';
@ -14,15 +16,6 @@ class STPPacket {
} }
} }
class KeyExchangePacket extends STPPacket {
constructor(key, type = 'pkcs8-pem') {
super();
this.cmd = 'KEY';
this.data.key = key;
this.meta.type = type;
}
}
function basicPacket(commandName) { function basicPacket(commandName) {
return class extends STPPacket { return class extends STPPacket {
constructor() { constructor() {
@ -32,7 +25,87 @@ function basicPacket(commandName) {
} }
} }
module.exports.STPPacket = STPPacket; // #endregion
// #region === [ exotic packet classes ] ===
class KeyExchangePacket extends STPPacket {
constructor(key, type = 'pkcs8-pem') {
super();
this.cmd = 'KEY';
this.data.key = key;
this.meta.type = type;
}
}
class ClientsPacket extends STPPacket {
constructor(clients) {
super();
this.cmd = 'NODES'
this.data.clients = clients;
}
}
class PingPacket extends STPPacket {
constructor() {
super();
this.cmd = 'PING';
this.data.id = md5(Date());
}
}
class PongPacket extends STPPacket {
constructor(id) {
super();
this.cmd = 'PONG';
this.data.id = id;
}
}
// #endregion
// #region === [ ordinary packet classes ] ===
const AckPacket = basicPacket('ACK');
const GetClientsPacket = basicPacket('QNODES');
// #endregion
// #region === [ public lib functions ] ===
function reconstructPacket(packet) {
if(packet.startsWith('\02'))
return reconstructPacket(packet.substr(1));
if(packet.endsWith('\x03'))
return reconstructPacket(packet.substr(0, packet.length - 1));
const obj = JSON.parse(packet);
switch(obj.cmd) {
case 'KEY': return new KeyExchangePacket(obj.data.key, obj.meta.type);
case 'NODES': return new ClientsPacket(obj.data.clients);
case 'QNODES': return new GetClientsPacket();
case 'ACK': return new AckPacket();
case 'NOOP': return new STPPacket();
default: throw new TypeError(`Unknown command ${obj.cmd}`);
}
}
// #endregion
// #region === [ exports ] ===
module.exports.KeyExchangePacket = KeyExchangePacket; module.exports.KeyExchangePacket = KeyExchangePacket;
module.exports.AckPacket = basicPacket('ACK') module.exports.ClientsPacket = ClientsPacket;
module.exports.GetClientsPacket = basicPacket('NODES') module.exports.PingPacket = PingPacket;
module.exports.PongPacket = PongPacket;
module.exports.AckPacket = AckPacket;
module.exports.GetClientsPacket = GetClientsPacket;
module.exports.reconstructPacket = reconstructPacket;
// #endregion

3
lib/appdata.js 100644
View File

@ -0,0 +1,3 @@
const appdata = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share");
module.exports = appdata;

39
lib/config.js 100644
View File

@ -0,0 +1,39 @@
const pkg = require('./../package.json');
const { readFileSync, writeFileSync } = require('fs');
const { ensureDirSync } = require('fs-extra');
const appdata = require('./appdata');
ensureDirSync(`${appdata}/valnet/relay`);
const filepath = `${appdata}/valnet/relay/config.json`;
const configObject = {}
module.exports.config = configObject;
module.exports.write = write;
function write() {
writeFileSync(filepath, JSON.stringify(configObject, null, 2));
}
function importFromPackage() {
loadObject(pkg.config);
}
function loadObject(obj) {
for(const key in obj) {
configObject[key] = obj[key];
}
write();
}
try {
const json = readFileSync(filepath);
const data = JSON.parse(json);
loadObject(data);
} catch(e) {
importFromPackage();
}

View File

@ -1,11 +1,111 @@
const EventEmitter = require('events') const EventEmitter = require('events')
const stp = require('./STP');
const upnp = require('./upnp');
const md5 = require('md5');
const pkg = require('./../package.json');
const { config, write } = require('./config.js');
const log = require('signale').scope('NODE');
const bonjour = require('bonjour')();
const Gateway = require('./Gateway');
class Node extends EventEmitter { class Node extends EventEmitter {
constructor() { clients = [];
hash = null;
name = null;
readyPromise = null;
port = null;
identity;
multicastAd = null;
multicastBrowser = null;
connected = false;
constructor(identity) {
super();
this.identity = identity;
this.hash = md5(identity.publicKey);
this.name = `valnet-node-${identity.name}`;
this.readyPromise = this.negotiatePort()
.then(this.startServer.bind(this))
.catch(this.serverStartupFailed.bind(this))
.then(this.connectNetwork.bind(this))
}
async connectNetwork() {
const gateway = new Gateway(this.identity, config.endpoints);
}
async serverStartupFailed(error) {
log.warn('Failed to set up Valet server on node.')
}
async startServer() {
log.info('creating Valnet Node on port ' + this.port + '...');
stp.createServer({
identity: this.identity,
port: this.port
}, (connection) => {
log.info('incomming connection from ' + connection.remoteAddress);
});
log.info('advertising node on multicast...')
this.multicastAd = bonjour.publish({
name: this.name,
type: 'STP',
port: this.port
});
this.multicastBrowser = bonjour.find({});
this.multicastBrowser.on('up', this.serviceUp.bind(this));
this.multicastBrowser.on('down', this.serviceDown.bind(this));
// log.success('Node successfully registered!');
}
async serviceUp({name, address, port, protocol}) {
// log.debug(`Found ${name} @ ${address}:${port} using ${protocol}`);
}
async serviceDown(service) {
log.debug('down', service);
}
async negotiatePort() {
const mappings = await upnp.mappings();
const matchingMappings = mappings.filter(mapping => {
return mapping.description === this.name
});
const alreadyMapped = matchingMappings.length > 0;
const takenPorts = mappings.map(mapping => mapping.public.port);
if(alreadyMapped) {
this.port = matchingMappings[0].public.port;
log.success(`upnp port ${this.port} already registered!`);
return;
}
for(let port = config.ports.relay; port <= config.ports.relayEnd; port ++) {
if(takenPorts.indexOf(port) === -1) {
await upnp.mapIndefinite(port, this.name);
this.port = port;
log.success(`registered upnp port ${this.port}`);
return;
}
}
// console.log(mappings, this.hash);
}
static get Node() {
return Node;
}
get ready() {
return this.readyPromise;
} }
} }
module.exports.Node = Node; module.exports = Node;

View File

View File

@ -1,31 +1,34 @@
const natUpnp = require('nat-upnp'); const natUpnp = require('nat-upnp');
const client = natUpnp.createClient(); const client = natUpnp.createClient();
module.exports.map = function(port) {
module.exports.map = function(port, ttl = 10, name = 'upnp application') {
return new Promise((res, rej) => { return new Promise((res, rej) => {
client.portMapping({ client.portMapping({
private: port, private: port,
public: port, public: port,
ttl: 10, ttl,
description: 'valnet' description: name
}, (err) => { }, (err) => {
if(err) rej(err); if(err) rej(err);
res(); res();
}); });
}); });
} };
module.exports.mapIndefinite = function(port) {
module.exports.mapIndefinite = function(port, name = 'upnp application') {
return new Promise((res, rej) => { return new Promise((res, rej) => {
client.portMapping({ client.portMapping({
private: port, private: port,
public: port, public: port,
ttl: 0, ttl: 0,
description: 'valnet' description: name
}, (err) => { }, (err) => {
if(err) rej(err); if(err) rej(err);
res(); res();
}); });
}); });
} };
module.exports.unmap = function(port) { module.exports.unmap = function(port) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
client.portUnmapping({ client.portUnmapping({
@ -36,7 +39,8 @@ module.exports.unmap = function(port) {
res(); res();
}); });
}); });
} };
module.exports.mappings = function() { module.exports.mappings = function() {
return new Promise((res, rej) => { return new Promise((res, rej) => {
client.getMappings((err, mappings) => { client.getMappings((err, mappings) => {
@ -44,7 +48,7 @@ module.exports.mappings = function() {
res(mappings); res(mappings);
}); });
}); });
} };
/* /*

View File

View File

@ -1,27 +0,0 @@
(async () => {
const { config } = require('./../package.json');
const net = require('net');
const dns = require('dns');
const stp = require('../lib/STP');
const os = require('os');
const { title } = require('../lib/title');
const { hri } = require('human-readable-ids');
const log = require('signale');
const Keyv = require('keyv');
const { KeyvFile } = require('keyv-file');
const kv = new Keyv({
store: new KeyvFile({
filename: `${os.tmpdir()}/valnet/name-server/data.json`
})
});
const { Identity } = require('./../lib/Identity');
title('Name Server');
const identity = new Identity('name-server', 'default');
})();

View File

@ -6,29 +6,34 @@
"config": { "config": {
"ports": { "ports": {
"relay": 5600, "relay": 5600,
"relayEnd": 5699,
"http": 5700, "http": 5700,
"service": 5000 "service": 5000
}, },
"addresses": { "addresses": {
"relay": "valnet.xyz" "relay": "valnet.xyz"
} },
"endpoints": [
"valnet.xyz:5500"
]
}, },
"scripts": { "scripts": {
"name-server": "supervisor -w name-server,lib -n exit name-server/index.js",
"relay": "supervisor -w relay,lib -n exit relay/index.js", "relay": "supervisor -w relay,lib -n exit relay/index.js",
"relay:service": "supervisor -- relay/service", "relay:service": "supervisor -- relay/service",
"client:a": "supervisor -w client,lib -n exit -- client/index.js --profile J2aV59rsIgcdd5k2", "sloc": "find lib -type f | xargs wc -l"
"client:b": "supervisor -w client,lib -n exit -- client/index.js --profile LsE8OnVzr1iYrkT0"
}, },
"dependencies": { "dependencies": {
"bonjour": "^3.5.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-ws": "^4.0.0", "express-ws": "^4.0.0",
"font-ascii": "^1.2.1", "font-ascii": "^1.2.1",
"fs-extra": "^9.1.0",
"gradient-string": "^1.2.0", "gradient-string": "^1.2.0",
"human-readable-ids": "^1.0.4", "human-readable-ids": "^1.0.4",
"ip": "^1.1.5", "ip": "^1.1.5",
"keyv": "^4.0.3", "keyv": "^4.0.3",
"keyv-file": "^0.2.0", "keyv-file": "^0.2.0",
"md5": "^2.3.0",
"nat-upnp": "^1.1.1", "nat-upnp": "^1.1.1",
"nedb": "^1.8.0", "nedb": "^1.8.0",
"node-rsa": "^1.1.1", "node-rsa": "^1.1.1",

View File

@ -1,51 +1,16 @@
(async () => { (async () => {
const { title } = require('../lib/title'); const { title } = require('../lib/title');
const net = require('net'); const log = require('signale').scope('RLAY');
const log = require('signale').scope('relay');
const { config } = require('../package.json');
const { Identity } = require('../lib/Identity'); const { Identity } = require('../lib/Identity');
const stp = require('../lib/STP');
title('relay', false); title('relay', false);
const identity = await new Identity('relay', 'default'); const identity = await new Identity('relay', 'default');
const upnp = require('../lib/upnp'); const Node = require('../lib/node');
const { config } = require('../lib/config');
const { ensureDirSync } = require('fs-extra');
const appdata = require('../lib/appdata');
const clients = []; ensureDirSync(`${appdata}/valnet/relay`);
const node = new Node(identity);
// const client = stp.connect(identity, config.ports.relay, '127.0.0.1');
// upnp.mapIndefinite(5600);
// ==================================== [STP SERVER]
stp.createServer({
identity: identity,
port: config.ports.relay
}, socket => {
log.info('secured connection from ' + socket.remoteAddress);
clients.push(socket);
});
function connectNetwork(t = 1000) {
if(t > 60000) t /= 2;
const client = stp.connect({
identity,
port: config.ports.relay,
ip: config.addresses.relay
});
client.on('ready', () => {
log.success('connectd to relay!');
t = 500;
})
client.on('error', e => {
});
client.on('close', e => {
t *= 2;
setTimeout(connectNetwork.bind(global, t), t);
log.warn('disconnected from relay');
log.warn('retrying connection... ' + (t/1000) + 's')
});
}
connectNetwork();
// ==================================== [EXPRESS] // ==================================== [EXPRESS]
const express = require('express'); const express = require('express');

View File

@ -1,5 +1,5 @@
(async () => { (async () => {
const log = require('signale').scope('service'); const log = require('signale').scope('SRVC');
const { execSync, spawn } = require('child_process'); const { execSync, spawn } = require('child_process');
const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim(); const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
let proc; let proc;
@ -12,6 +12,12 @@ const { config } = require('../package.json');
const express = require('express'); const express = require('express');
const app = express(); const app = express();
try {
appendLogs('yarn', execSync(`yarn`));
} catch (e) {
appendLogs('failed to yarn install...')
}
logp('=================================='); logp('==================================');
logp('Starting Valnet Node as a Service!'); logp('Starting Valnet Node as a Service!');
logp('Syncing to branch: ' + branch); logp('Syncing to branch: ' + branch);
@ -130,14 +136,14 @@ ${docs.map(logItem => logItem.message).join('').replace(/\u001B\[.*?[A-Za-z]/g,
</pre> </pre>
<br><br><br><br><br><br> <br><br><br><br><br><br>
<script> <script>
requestAnimationFrame(_ => { // requestAnimationFrame(_ => {
requestAnimationFrame(_ => { // requestAnimationFrame(_ => {
window.scrollTo(0,document.body.scrollHeight); // window.scrollTo(0,document.body.scrollHeight);
}); // });
}); // });
setTimeout(_ => { // setTimeout(_ => {
location.reload(); // location.reload();
}, 2000); // }, 2000);
</script> </script>
</body> </body>
</html> </html>

View File

@ -41,8 +41,6 @@ function searchGateway(timeout, callback) {
} }
var onlistening = function() { var onlistening = function() {
console.log('listening?')
socket.setBroadcast(socket.fd, true); socket.setBroadcast(socket.fd, true);
// send a few packets just in case. // send a few packets just in case.

160
yarn.lock
View File

@ -52,6 +52,10 @@ array-flatten@1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
array-flatten@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
array-includes@^3.1.1: array-includes@^3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348"
@ -95,6 +99,11 @@ asynckit@^0.4.0:
version "0.4.0" version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
at-least-node@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
aws-sign2@~0.7.0: aws-sign2@~0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
@ -134,6 +143,17 @@ body-parser@1.19.0:
raw-body "2.4.0" raw-body "2.4.0"
type-is "~1.6.17" type-is "~1.6.17"
bonjour@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5"
dependencies:
array-flatten "^2.1.0"
deep-equal "^1.0.1"
dns-equal "^1.0.0"
dns-txt "^2.0.2"
multicast-dns "^6.0.1"
multicast-dns-service-types "^1.1.0"
brace-expansion@^1.1.7: brace-expansion@^1.1.7:
version "1.1.11" version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -141,6 +161,10 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0" balanced-match "^1.0.0"
concat-map "0.0.1" concat-map "0.0.1"
buffer-indexof@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c"
bytes@3.1.0: bytes@3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
@ -152,6 +176,13 @@ call-bind@^1.0.0:
function-bind "^1.1.1" function-bind "^1.1.1"
get-intrinsic "^1.0.0" get-intrinsic "^1.0.0"
call-bind@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
dependencies:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"
caseless@~0.12.0: caseless@~0.12.0:
version "0.12.0" version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
@ -175,6 +206,10 @@ chardet@^0.7.0:
version "0.7.0" version "0.7.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
charenc@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
cli-cursor@^3.1.0: cli-cursor@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
@ -253,6 +288,10 @@ core-util-is@1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
crypt@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
dashdash@^1.12.0: dashdash@^1.12.0:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@ -271,6 +310,17 @@ debug@^4.1.1:
dependencies: dependencies:
ms "2.1.2" ms "2.1.2"
deep-equal@^1.0.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
dependencies:
is-arguments "^1.0.4"
is-date-object "^1.0.1"
is-regex "^1.0.4"
object-is "^1.0.1"
object-keys "^1.1.1"
regexp.prototype.flags "^1.2.0"
define-properties@^1.1.3: define-properties@^1.1.3:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@ -289,6 +339,23 @@ destroy@~1.0.4:
version "1.0.4" version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
dns-packet@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a"
dependencies:
ip "^1.1.0"
safe-buffer "^5.0.1"
dns-txt@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6"
dependencies:
buffer-indexof "^1.0.0"
doctrine@1.5.0: doctrine@1.5.0:
version "1.5.0" version "1.5.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
@ -594,6 +661,16 @@ fs-extra@^4.0.1:
jsonfile "^4.0.0" jsonfile "^4.0.0"
universalify "^0.1.0" universalify "^0.1.0"
fs-extra@^9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
dependencies:
at-least-node "^1.0.0"
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"
function-bind@^1.1.1: function-bind@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@ -610,6 +687,14 @@ get-intrinsic@^1.0.0:
has "^1.0.3" has "^1.0.3"
has-symbols "^1.0.1" has-symbols "^1.0.1"
get-intrinsic@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
getpass@^0.1.1: getpass@^0.1.1:
version "0.1.7" version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
@ -620,6 +705,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6:
version "4.2.4" version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
graceful-fs@^4.2.0:
version "4.2.6"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
gradient-string@^1.2.0: gradient-string@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/gradient-string/-/gradient-string-1.2.0.tgz#93f39f2c7c8dcb095608c2ccf0aac24aa315fbac" resolved "https://registry.yarnpkg.com/gradient-string/-/gradient-string-1.2.0.tgz#93f39f2c7c8dcb095608c2ccf0aac24aa315fbac"
@ -734,7 +824,7 @@ inquirer@^7.0.0:
strip-ansi "^6.0.0" strip-ansi "^6.0.0"
through "^2.3.6" through "^2.3.6"
ip@^1.1.4, ip@^1.1.5: ip@^1.1.0, ip@^1.1.4, ip@^1.1.5:
version "1.1.5" version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
@ -742,10 +832,20 @@ ipaddr.js@1.9.1:
version "1.9.1" version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
is-arguments@^1.0.4:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9"
dependencies:
call-bind "^1.0.0"
is-arrayish@^0.2.1: is-arrayish@^0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
is-buffer@~1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
is-callable@^1.1.4, is-callable@^1.2.2: is-callable@^1.1.4, is-callable@^1.2.2:
version "1.2.2" version "1.2.2"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
@ -768,6 +868,13 @@ is-negative-zero@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461"
is-regex@^1.0.4:
version "1.1.2"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251"
dependencies:
call-bind "^1.0.2"
has-symbols "^1.0.1"
is-regex@^1.1.1: is-regex@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
@ -832,6 +939,15 @@ jsonfile@^4.0.0:
optionalDependencies: optionalDependencies:
graceful-fs "^4.1.6" graceful-fs "^4.1.6"
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
jsprim@^1.2.2: jsprim@^1.2.2:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
@ -900,6 +1016,14 @@ lodash@^4.17.14, lodash@^4.17.19:
version "4.17.20" version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
md5@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
dependencies:
charenc "0.0.2"
crypt "0.0.2"
is-buffer "~1.1.6"
media-typer@0.3.0: media-typer@0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -968,6 +1092,17 @@ ms@2.1.2:
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
multicast-dns-service-types@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
multicast-dns@^6.0.1:
version "6.2.3"
resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229"
dependencies:
dns-packet "^1.3.1"
thunky "^1.0.2"
mute-stream@0.0.8: mute-stream@0.0.8:
version "0.0.8" version "0.0.8"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
@ -1018,6 +1153,13 @@ object-inspect@^1.8.0:
version "1.8.0" version "1.8.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
object-is@^1.0.1:
version "1.1.5"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.3"
object-keys@^1.0.12, object-keys@^1.1.1: object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@ -1191,6 +1333,13 @@ read-pkg@^2.0.0:
normalize-package-data "^2.3.2" normalize-package-data "^2.3.2"
path-type "^2.0.0" path-type "^2.0.0"
regexp.prototype.flags@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26"
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.3"
regexpp@^3.0.0: regexpp@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
@ -1407,6 +1556,10 @@ through@^2.3.6:
version "2.3.8" version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
thunky@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
tinycolor2@^1.0.0: tinycolor2@^1.0.0:
version "1.4.2" version "1.4.2"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803"
@ -1477,6 +1630,11 @@ universalify@^0.1.0:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
unpipe@1.0.0, unpipe@~1.0.0: unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"