25 Commits

Author SHA1 Message Date
Colfax Selby
410df9c1be nit 2021-03-26 09:33:53 -04:00
Colfax Selby
a904442c55 Loading state for status page 2021-03-26 09:22:38 -04:00
Colfax Selby
9c444bca35 Add setTimeout to status page load as well, noticed slowness 2021-03-26 09:16:48 -04:00
Colfax Selby
f9d9b75b1b add client name to log window title 2021-03-26 09:12:05 -04:00
Colfax Selby
4dbe342a91 CSS 2021-03-26 08:59:29 -04:00
Colfax Selby
04dd67cd88 Fix timeout, minor text edits 2021-03-26 08:57:03 -04:00
Colfax Selby
e08a38221e Title in quotes 2021-03-25 22:32:46 -04:00
Colfax Selby
d3302cf08e Fix logs, client name UI tweak 2021-03-25 22:30:12 -04:00
Colfax Selby
937a70fc79 fix logs; fcn to wrap group 2021-03-25 22:05:31 -04:00
Colfax Selby
3787fd0217 Fix node logs commands 2021-03-25 21:51:51 -04:00
Colfax Selby
996049e3d7 Fix docker status commands 2021-03-25 21:50:08 -04:00
Colfax Selby
e29a377df4 Rework install with new password flow 2021-03-25 20:39:38 -04:00
Colfax Selby
6e501d0798 Lets try su again 2021-03-25 20:29:11 -04:00
Colfax Selby
aa2c997afd remove sync wait 2021-03-25 20:18:08 -04:00
Colfax Selby
81dfb46a18 Add full path executable back 2021-03-25 19:58:19 -04:00
Colfax Selby
0ad9ef976d Utilize askpass for password prompt 2021-03-25 19:32:01 -04:00
Colfax Selby
ef4ce6ab92 executable back to path 2021-03-25 17:15:16 -04:00
Colfax Selby
7ea6d5aae8 source to . 2021-03-25 16:17:40 -04:00
Colfax Selby
424ab11755 source to . 2021-03-25 16:15:56 -04:00
Colfax Selby
19abe323b8 Pause after sync execute, source profile 2021-03-25 16:14:06 -04:00
Colfax Selby
001bebe9c4 No longer fetch full path 2021-03-25 16:02:04 -04:00
Colfax Selby
efe3cbc586 Run sudo before install to cache credentials 2021-03-25 15:21:30 -04:00
Colfax Selby
1b87ce9ee5 Call newgrp to set docker group immediately 2021-03-25 14:48:47 -04:00
Colfax Selby
e00783b692 Cleanup install fix 2021-03-24 15:49:37 -04:00
Colfax Selby
7d61a20517 Dont run install as root 2021-03-24 15:40:52 -04:00
7 changed files with 68 additions and 234 deletions

View File

@@ -29,7 +29,6 @@
"@rauschma/stringio": "^1.4.0",
"html-webpack-plugin": "^5.2.0",
"js-yaml": "^4.0.0",
"node-docker-api": "^1.1.22",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router-dom": "^5.2.0",

View File

@@ -26,15 +26,15 @@ const executeCommandAsync = async (cmd: string): Promise<any> => {
});
}
const executeCommandInNewTerminal = (cmd: string): number => {
return executeCommandSync(UBUNTU_TERMINAL_COMMAND + " -- bash -c '" + cmd + "'");
const executeCommandInNewTerminal = (cmd: string, title: string): number => {
return executeCommandSync(UBUNTU_TERMINAL_COMMAND + " --title=\"" + title + "\" -- bash -c '" + cmd + "'");
}
const executeCommandSync = (cmd: string): number => {
console.log("running command sync with: " + cmd);
try {
execSync(cmd);
execSync(cmd, {stdio: 'inherit'});
return 0;
}
catch (error) {
@@ -92,6 +92,7 @@ const syncWait = (ms: number) => {
}
async function writeToWritable(writable: Writable, responses: string[]) {
syncWait(1000);
for (const response of responses) {
console.log("writing '" + response + "'");
await streamWrite(writable, response);

View File

@@ -1,11 +1,11 @@
import { doesFileExist, readlink } from "./BashUtils";
import { executeCommandAsync, executeCommandInNewTerminal, executeCommandSync, executeCommandSyncReturnStdout, executeCommandWithPromptsAsync } from "./ExecuteCommand";
import { executeCommandInNewTerminal, executeCommandSync, executeCommandSyncReturnStdout, executeCommandWithPromptsAsync } from "./ExecuteCommand";
import { Container } from 'node-docker-api/lib/container';
import { Docker } from "node-docker-api";
import fs from "fs";
import yaml from "js-yaml";
const ASKPASS_PATH = "src/scripts/askpass.sh";
const ROCKET_POOL_EXECUTABLE = "~/bin/rocketpool";
const ROCKET_POOL_DIR = "~/.rocketpool"
const ROCKET_POOL_INSTALL_COMMAND = "curl -L https://github.com/rocket-pool/smartnode-install/releases/latest/download/rocketpool-cli-linux-amd64 --create-dirs -o " + ROCKET_POOL_EXECUTABLE + " && chmod +x " + ROCKET_POOL_EXECUTABLE;
@@ -21,7 +21,9 @@ const GETH_PEERS_DOCKER_CMD = "docker exec rocketpool_eth1 geth --exec 'admin.pe
type Callback = (success: boolean) => void;
type NodeStatusCallback = (status: number) => void;
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
const wrapCommandInDockerGroup = (command: string) => {
return "sg docker \"" + command + "\"";
}
// TODO: make this better, it is pretty brittle and peeks into the RP settings implementation
// this is required because we select the client at random, so we need to show the user what is running
@@ -37,7 +39,15 @@ const getEth2ClientName = (): string => {
}
}
const installAndStartRocketPool = async (password: string, callback: Callback) => {
const installAndStartRocketPool = async (callback: Callback) => {
// cache sudo credentials to be used for install later
const passwordRc = executeCommandSync("export SUDO_ASKPASS='" + ASKPASS_PATH + "' && sudo -A echo 'Authentication successful.'");
if (passwordRc != 0) {
console.log("password failed");
callback(false);
return;
}
const cliRc = executeCommandSync(ROCKET_POOL_INSTALL_COMMAND);
if (cliRc != 0) {
console.log("cli failed to install");
@@ -45,19 +55,19 @@ const installAndStartRocketPool = async (password: string, callback: Callback) =
return;
}
const serviceRc = executeCommandSync(ROCKET_POOL_EXECUTABLE + " service install --yes --network pyrmont")
if (serviceRc != 0) {
console.log("service install failed");
callback(false);
return;
}
// For some reason executeCommandWithPromptsAsync needs the full path, so fetching it here
const rocketPoolExecutableFullPath = readlink(ROCKET_POOL_EXECUTABLE);
console.log("full path");
console.log(rocketPoolExecutableFullPath);
const serviceRc = await executeCommandAsync("echo " + password + " | sudo -S " + rocketPoolExecutableFullPath + " --allow-root service install --yes --network pyrmont");
if (serviceRc != 0) {
console.log("service install failed to install");
callback(false);
return;
}
const promptRepsonses = [
const promptResponses = [
"1\n", // which eth1 client? 1 geth, 2 infura, 3 custom
"\n", // ethstats label
"\n", // ethstats login
@@ -65,7 +75,7 @@ const installAndStartRocketPool = async (password: string, callback: Callback) =
"\n" // graffiti
]
const serviceConfigRc = await executeCommandWithPromptsAsync(rocketPoolExecutableFullPath, ["service", "config"], promptRepsonses);
const serviceConfigRc = await executeCommandWithPromptsAsync(rocketPoolExecutableFullPath, ["service", "config"], promptResponses);
if (serviceConfigRc != 0) {
console.log("service config failed");
callback(false);
@@ -93,7 +103,7 @@ const isRocketPoolInstalled = (): boolean => {
}
const openEth1Logs = () => {
const openEth1LogsRc = executeCommandInNewTerminal(ROCKET_POOL_EXECUTABLE + " service logs eth1");
const openEth1LogsRc = executeCommandInNewTerminal(wrapCommandInDockerGroup("docker container logs -f rocketpool_eth1"), "eth1 (geth) logs");
if (openEth1LogsRc != 0) {
console.log("failed to open eth1 logs");
return;
@@ -101,7 +111,7 @@ const openEth1Logs = () => {
}
const openEth2BeaconLogs = () => {
const openEth2BeaconLogsRc = executeCommandInNewTerminal(ROCKET_POOL_EXECUTABLE + " service logs eth2");
const openEth2BeaconLogsRc = executeCommandInNewTerminal(wrapCommandInDockerGroup("docker container logs -f rocketpool_eth2"), "eth2 beacon node (" + getEth2ClientName() + ") logs");
if (openEth2BeaconLogsRc != 0) {
console.log("failed to open eth2 beacon logs");
return;
@@ -109,7 +119,7 @@ const openEth2BeaconLogs = () => {
}
const openEth2ValidatorLogs = () => {
const openEth2ValidatorLogsRc = executeCommandInNewTerminal(ROCKET_POOL_EXECUTABLE + " service logs validator");
const openEth2ValidatorLogsRc = executeCommandInNewTerminal(wrapCommandInDockerGroup("docker container logs -f rocketpool_validator"), "eth2 validator (" + getEth2ClientName() + ") logs");
if (openEth2ValidatorLogsRc != 0) {
console.log("failed to open eth2 validator logs");
return;
@@ -117,15 +127,15 @@ const openEth2ValidatorLogs = () => {
}
const startNodes = (): number => {
return executeCommandSync(ROCKET_POOL_EXECUTABLE + " service start");
return executeCommandSync(wrapCommandInDockerGroup(ROCKET_POOL_EXECUTABLE + " service start"));
}
const stopNodes = (): number => {
return executeCommandSync(ROCKET_POOL_EXECUTABLE + " service stop -y");
return executeCommandSync(wrapCommandInDockerGroup(ROCKET_POOL_EXECUTABLE + " service stop -y"));
}
const queryEth1PeerCount = (): number => {
const numPeers = executeCommandSyncReturnStdout(GETH_PEERS_DOCKER_CMD);
const numPeers = executeCommandSyncReturnStdout(wrapCommandInDockerGroup(GETH_PEERS_DOCKER_CMD));
const numPeersNumber = parseInt(numPeers.trim());
return isNaN(numPeersNumber) ? 0 : numPeersNumber;
}
@@ -135,7 +145,7 @@ const queryEth1Status = (nodeStatusCallback: NodeStatusCallback) => {
}
const queryEth1Syncing = (): boolean => {
const syncValue = executeCommandSyncReturnStdout(GETH_SYNC_STATUS_DOCKER_CMD);
const syncValue = executeCommandSyncReturnStdout(wrapCommandInDockerGroup(GETH_SYNC_STATUS_DOCKER_CMD));
return !syncValue.includes("false");
}
@@ -147,29 +157,14 @@ const queryEth2ValidatorStatus = (nodeStatusCallback: NodeStatusCallback) => {
dockerContainerStatus("rocketpool_validator", nodeStatusCallback);
}
// TODO: make this better - it is very fragile
const dockerContainerStatus = async (containerName: string, nodeStatusCallback: NodeStatusCallback) => {
docker.container.list().then(
(containers: Container[]) => {
const filteredContainers = containers.filter((container => {
const data: any = container.data;
return data["Names"][0].includes(containerName);
}))
const containerId = executeCommandSyncReturnStdout(wrapCommandInDockerGroup("docker ps -q -f name=" + containerName));
if (filteredContainers.length == 0) {
nodeStatusCallback(2); // offline
} else {
const containerData: any = filteredContainers[0].data;
const containerState: string = containerData["State"];
if (containerState.includes("running")) {
nodeStatusCallback(0); // online
} else {
nodeStatusCallback(2); // offline
}
}
}).catch(() => {
nodeStatusCallback(2); // offline
})
if (containerId.trim()) {
nodeStatusCallback(0); // online
} else {
nodeStatusCallback(2); // offline
}
}
export {

View File

@@ -6,7 +6,7 @@ import {
MainContent
} from "../colors";
import { Link, withRouter } from "react-router-dom";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import styled, { keyframes } from "styled-components";
import { History } from "history";
@@ -38,10 +38,6 @@ const Content = styled.div`
flex-grow: 6;
`;
const StyledInput = styled.input`
width: 100px;
`;
const rotate = keyframes`
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
@@ -57,99 +53,19 @@ const LoadingSpinner = styled.div`
border: 16px solid #f3f3f3; /* Light grey */
border-top: 16px solid #3498db; /* Blue */
border-radius: 50%;
margin-top: 30px;
width: 120px;
height: 120px;
animation: ${rotate} 2s linear infinite;
`;
const FooterContainer = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
align-self: flex-end;
height: 70;
flex-grow:1;
min-width:100vw;
`;
const InputContainer = styled.div`
width: 100%;
display: flex;
flex-direction: row;
justify-content: center;
`;
const ContinueButton = styled.div`
color: ${Black};
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
align-self:flex-end;
height: 24;
background-color: ${Button};
padding: 16 24;
border-radius: 10%;
text-decoration: none;
transition: 250ms background-color ease;
cursor: pointer;
margin: 60;
&:hover {
background-color: ${ButtonHover};
}
`;
const StyledButton = styled(Link)`
color: ${Black};
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
align-self:flex-end;
height: 24;
background-color: ${Button};
padding: 16 24;
border-radius: 10%;
text-decoration: none;
transition: 250ms background-color ease;
cursor: pointer;
margin: 60;
&:hover {
background-color: ${ButtonHover};
}
`;
const Installing = ({ history }: {history: History}) => {
const [password, setPassword] = useState("");
const [installInProgress, setInstallInProgress] = useState(false);
const handleChangePassword = (event: { target: { value: React.SetStateAction<string>; }; }) => {
setPassword(event.target.value);
}
const handleKeyPressed = (event: { keyCode: any; which: any; }) => {
var code = event.keyCode || event.which;
if(code === ENTER_KEYCODE) {
handleSubmitPassword();
}
}
const handleSubmitPassword = () => {
// TODO: handle wrong password
// TODO: handle empty password
setInstallInProgress(true);
// Without this setTimeout, there was a pause before the screen would update saying Installing...
useEffect(() => {
setTimeout(() => {
installAndStartRocketPool(password, installCallback);
}, 2000);
}
installAndStartRocketPool(installCallback);
}, 1000);
}, [])
const installCallback = (success: boolean) => {
if (success) {
@@ -168,36 +84,15 @@ const Installing = ({ history }: {history: History}) => {
return (
<Container>
<LandingHeader>Install</LandingHeader>
{ installInProgress ?
<Content>
Installing...
<br />
<br />
May take up to 2 minutes.
May take 2-4 minutes depending on internet speed.
<SpinnerContainer>
<LoadingSpinner />
</SpinnerContainer>
</Content> :
<Content>
In order to download the necessary software, we must have admin access to your computer.
<br />
<br />
Please enter you computer login password* below. Don't worry, we'll keep it safe.
<br />
<br />
<InputContainer>
<StyledInput type="password" value={password} onChange={handleChangePassword} onKeyPress={handleKeyPressed} />
</InputContainer>
<br />
<br />
*Note: at this stage we cannot handle password retries, so please get it right ;)
</Content>
}
<FooterContainer>
<StyledButton to="/systemcheck">Back</StyledButton>
<ContinueButton onClick={handleSubmitPassword}>Continue</ContinueButton>
</FooterContainer>
</Container>
)
}

View File

@@ -80,24 +80,27 @@ const LogsButton = styled.button`
const NodeStatus: [string, string, string][] = [
["Online", "\u2B24", "green"], // 0
["Syncing", "\u2B24", "yellow"], // 1
["Offline", "\u2B24", "red"] // 2
["Offline", "\u2B24", "red"], // 2
["Loading...", "", ""] // 3
]
// TODO: right after install, while nodes are starting up, this page says everything is "online"
// while things are looking for peers. Need to improve that logic.
const Status = () => {
const [eth1ContainerStatus, setEth1ContainerStatus] = useState(2);
const [eth1ContainerStatus, setEth1ContainerStatus] = useState(3);
const [eth1PeerCount, setEth1PeerCount] = useState(0);
const [eth1Syncing, setEth1Syncing] = useState(false);
const [eth2ClientName, setEth2ClientName] = useState("");
const [eth2BeaconContainerStatus, setEth2BeaconContainerStatus] = useState(2);
const [eth2ValidatorContainerStatus, setEth2ValidatorContainerStatus] = useState(2);
const [eth2BeaconContainerStatus, setEth2BeaconContainerStatus] = useState(3);
const [eth2ValidatorContainerStatus, setEth2ValidatorContainerStatus] = useState(3);
useEffect(() => {
queryStatuses();
setEth2ClientName(getEth2ClientName());
setInterval(queryStatuses, 5000);
setTimeout(() => {
queryStatuses();
setEth2ClientName(getEth2ClientName());
setInterval(queryStatuses, 5000);
}, 500)
}, []);
const queryStatuses = () => {
@@ -119,7 +122,9 @@ const Status = () => {
}
const computeEth1Status = (): number => {
if (eth1ContainerStatus == 2) {
if (eth1ContainerStatus == 3) {
return 3;
} else if (eth1ContainerStatus == 2) {
return 2;
} else if (eth1Syncing) {
return 1;
@@ -149,19 +154,19 @@ const Status = () => {
</thead>
<tbody>
<tr>
<td>Eth1 Node</td>
<td>Eth1 Node - geth</td>
<td>{formatStatusIcon(computeEth1Status())} {NodeStatus[computeEth1Status()][0]}</td>
<td>{eth1PeerCount}</td>
<td><LogsButton onClick={openEth1Logs} disabled={eth1ContainerStatus == 2}>View Logs</LogsButton></td>
</tr>
<tr>
<td>Eth2 Beacon Node</td>
<td>Eth2 Beacon Node - {eth2ClientName}</td>
<td>{formatStatusIcon(computeEth2BeaconStatus())} {NodeStatus[computeEth2BeaconStatus()][0]}</td>
<td>-</td>
<td><LogsButton onClick={openEth2BeaconLogs} disabled={eth2BeaconContainerStatus == 2}>View Logs</LogsButton></td>
</tr>
<tr>
<td>Eth2 Validator</td>
<td>Eth2 Validator - {eth2ClientName}</td>
<td>{formatStatusIcon(computeEth2ValidatorStatus())} {NodeStatus[computeEth2ValidatorStatus()][0]}</td>
<td>-</td>
<td><LogsButton onClick={openEth2ValidatorLogs} disabled={eth2ValidatorContainerStatus == 2}>View Logs</LogsButton></td>
@@ -231,8 +236,6 @@ const Status = () => {
<Content>
{ renderNodeStatusTable() }
<br />
Eth2 client: {eth2ClientName}
<br />
<br />
*Note: "Syncing" state is only supported for Eth1. Eth1 Beacon/Validator statuses are set based on docker status.
<br />

2
src/scripts/askpass.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
zenity --password --title=Authentication

View File

@@ -508,14 +508,6 @@
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
JSONStream@0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-0.10.0.tgz#74349d0d89522b71f30f0a03ff9bd20ca6f12ac0"
integrity sha1-dDSdDYlSK3HzDwoD/5vSDKbxKsA=
dependencies:
jsonparse "0.0.5"
through ">=2.2.7 <3"
accepts@^1.3.5:
version "1.3.7"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
@@ -1026,7 +1018,7 @@ debug@*, debug@^4.1.0, debug@^4.1.1:
dependencies:
ms "2.1.2"
debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@@ -1142,16 +1134,6 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"
docker-modem@^0.3.1:
version "0.3.7"
resolved "https://registry.yarnpkg.com/docker-modem/-/docker-modem-0.3.7.tgz#3f510d09f5d334dc2134228f92bd344671227df4"
integrity sha1-P1ENCfXTNNwhNCKPkr00RnEiffQ=
dependencies:
JSONStream "0.10.0"
debug "^2.6.0"
readable-stream "~1.0.26-4"
split-ca "^1.0.0"
dom-converter@^0.2:
version "0.2.0"
resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
@@ -1888,7 +1870,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -2141,11 +2123,6 @@ jsonfile@^4.0.0:
optionalDependencies:
graceful-fs "^4.1.6"
jsonparse@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-0.0.5.tgz#330542ad3f0a654665b778f3eb2d9a9fa507ac64"
integrity sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=
keygrip@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226"
@@ -2397,11 +2374,6 @@ memory-fs@^0.5.0:
errno "^0.1.3"
readable-stream "^2.0.1"
memorystream@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI=
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -2556,14 +2528,6 @@ no-case@^3.0.4:
lower-case "^2.0.2"
tslib "^2.0.3"
node-docker-api@^1.1.22:
version "1.1.22"
resolved "https://registry.yarnpkg.com/node-docker-api/-/node-docker-api-1.1.22.tgz#230327efd309a6ec7302bf3f404ab760040a5806"
integrity sha1-IwMn79MJpuxzAr8/QEq3YAQKWAY=
dependencies:
docker-modem "^0.3.1"
memorystream "^0.3.1"
node-releases@^1.1.70:
version "1.1.71"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
@@ -3005,16 +2969,6 @@ readable-stream@^3.1.1:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readable-stream@~1.0.26-4:
version "1.0.34"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "0.0.1"
string_decoder "~0.10.x"
rechoir@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca"
@@ -3381,11 +3335,6 @@ spdx-license-ids@^3.0.0:
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65"
integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==
split-ca@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6"
integrity sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=
split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
@@ -3418,11 +3367,6 @@ string_decoder@^1.1.1:
dependencies:
safe-buffer "~5.2.0"
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@@ -3536,11 +3480,6 @@ terser@^5.5.1:
source-map "~0.7.2"
source-map-support "~0.5.19"
"through@>=2.2.7 <3":
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
tiny-invariant@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"